import Store from "../store";
import {
  replaceHtml,
  getObjType,
  chatatABC,
  luckysheetactiveCell,
} from "../utils/util";
import {
  getSheetIndex,
  getluckysheet_select_save,
  getluckysheetfile,
} from "../methods/get";
import locale from "../locale/locale";
import method from "./method";
import formula from "./formula";
import func_methods from "./func_methods";
import tooltip from "./tooltip";
import json from "./json";
import editor from "./editor";
import luckysheetformula from "./formula";
import cleargridelement from "./cleargridelement";
import { genarate, update } from "./format";
import { setAccuracy, setcellvalue } from "./setdata";
import { orderbydata } from "./sort";
import { rowlenByRange } from "./getRowlen";
import { getdatabyselection, getcellvalue } from "./getdata";
import {
  luckysheetrefreshgrid,
  jfrefreshgrid,
  jfrefreshgrid_rhcw,
} from "./refresh";
import {
  luckysheetDeleteCell,
  luckysheetextendtable,
  luckysheetdeletetable,
} from "./extend";
import {
  isRealNull,
  valueIsError,
  isRealNum,
  isEditMode,
  hasPartMC,
} from "./validate";
import { isdatetime, diff } from "./datecontroll";
import { getBorderInfoCompute } from "./border";
import { luckysheetDrawMain } from "./draw";
import pivotTable from "../controllers/pivotTable";
import server from "../controllers/server";
import menuButton from "../controllers/menuButton";
import selection from "../controllers/selection";
import luckysheetConfigsetting from "../controllers/luckysheetConfigsetting";
import luckysheetFreezen from "../controllers/freezen";
import luckysheetsizeauto from "../controllers/resize";
import sheetmanage from "../controllers/sheetmanage";
import conditionformat from "../controllers/conditionformat";
import { luckysheet_searcharray } from "../controllers/sheetSearch";
import { selectHightlightShow, selectIsOverlap } from "../controllers/select";
import { sheetHTML, luckysheetdefaultstyle } from "../controllers/constant";
import { createFilterOptions } from "../controllers/filter";
import controlHistory from "../controllers/controlHistory";
import { zoomRefreshView, zoomNumberDomBind } from "../controllers/zoom";
import dataVerificationCtrl from "../controllers/dataVerificationCtrl";
import imageCtrl from "../controllers/imageCtrl";
import dayjs from "dayjs";
import { getRangetxt } from "../methods/get";
import { luckysheetupdateCell } from "../controllers/updateCell";
const IDCardReg = /^\d{6}(18|19|20)?\d{2}(0[1-9]|1[12])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/i;

/**
 * 获取单元格的值
 * @param {Number} row 单元格所在行数；从0开始的整数，0表示第一行
 * @param {Number} column 单元格所在列数；从0开始的整数，0表示第一列
 * @param {Object} options 可选参数
 * @param {String} options.type 单元格的值类型，可以设置为原始值"v"或者显示值"m"；默认值为'v',表示获取单元格的实际值
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 */
export function getCellValue(row, column, options = {}) {
  if (!isRealNum(row) || !isRealNum(column)) {
    return tooltip.info(
      "Arguments row or column cannot be null or undefined.",
      ""
    );
  }
  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let { type = "v", order = curSheetOrder } = { ...options };
  let targetSheetData = Store.luckysheetfile[order].data;
  let cellData = targetSheetData[row][column];
  let return_v;

  if (getObjType(cellData) == "object") {
    return_v = cellData[type];

    if (type == "f" && return_v != null) {
      return_v = formula.functionHTMLGenerate(return_v);
    } else if (type == "f") {
      return_v = cellData["v"];
    } else if (cellData && cellData.ct) {
      if (cellData.ct.fa == "yyyy-MM-dd") {
        return_v = cellData.m;
      }
      // 修复当单元格内有换行获取不到值的问题
      else if (
        cellData.ct.hasOwnProperty("t") &&
        cellData.ct.t === "inlineStr"
      ) {
        let inlineStrValueArr = cellData.ct.s;
        if (inlineStrValueArr) {
          return_v = inlineStrValueArr.map((i) => i.v).join("");
        }
      }
    }
  }

  if (return_v == undefined) {
    return_v = null;
  }

  return return_v;
}

/**
 * 设置单元格的值
 *
 * 关键点：如果设置了公式，则需要更新公式链insertUpdateFunctionGroup，如果设置了不是公式，判断之前是公式，则需要清除公式delFunctionGroup
 *
 * @param {Number} row 单元格所在行数；从0开始的整数，0表示第一行
 * @param {Number} column 单元格所在列数；从0开始的整数，0表示第一列
 * @param {Object | String | Number} value 要设置的值；可以为字符串或数字，或为符合Luckysheet单元格格式的对象
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Boolean} options.isRefresh 是否刷新界面；默认为`true`
 * @param {Function} options.success 操作结束的回调函数
 */
export function setCellValue(row, column, value, options = {}) {
  let curv = Store.flowdata[row][column];

  // Store old value for hook function
  const oldValue = JSON.stringify(curv);

  if (!isRealNum(row) || !isRealNum(column)) {
    return tooltip.info("The row or column parameter is invalid.", "");
  }

  let {
    order = getSheetIndex(Store.currentSheetIndex),
    isRefresh = true,
    success,
  } = { ...options };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  /* cell更新前触发  */
  if (
    !method.createHookFunction(
      "cellUpdateBefore",
      row,
      column,
      value,
      isRefresh
    )
  ) {
    /* 如果cellUpdateBefore函数返回false 则不执行后续的更新 */
    return;
  }

  let data = file.data;
  if (isRefresh) {
    data = $.extend(true, [], file.data);
  }
  if (data.length == 0) {
    data = sheetmanage.buildGridData(file);
  }

  // luckysheetformula.updatecell(row, column, value);
  let formatList = {
    //ct:1, //celltype,Cell value format: text, time, etc.
    bg: 1, //background,#fff000
    ff: 1, //fontfamily,
    fc: 1, //fontcolor
    bl: 1, //Bold
    it: 1, //italic
    fs: 1, //font size
    cl: 1, //Cancelline, 0 Regular, 1 Cancelline
    un: 1, //underline, 0 Regular, 1 underlines, fonts
    vt: 1, //Vertical alignment, 0 middle, 1 up, 2 down
    ht: 1, //Horizontal alignment,0 center, 1 left, 2 right
    mc: 1, //Merge Cells
    tr: 1, //Text rotation,0: 0、1: 45 、2: -45、3 Vertical text、4: 90 、5: -90
    tb: 1, //Text wrap,0 truncation, 1 overflow, 2 word wrap
    //v: 1, //Original value
    //m: 1, //Display value
    rt: 1, //text rotation angle 0-180 alignment
    //f: 1, //formula
    qp: 1, //quotePrefix, show number as string
  };

  if (value == null || value.toString().length == 0) {
    formula.delFunctionGroup(row, column);
    setcellvalue(row, column, data, value);
  } else if (value instanceof Object) {
    let curv = {};
    if (isRealNull(data[row][column])) {
      data[row][column] = {};
    }
    let cell = data[row][column];
    if (value.f != null && value.v == null) {
      curv.f = value.f;
      if (value.ct != null) {
        curv.ct = value.ct;
      }
      data = luckysheetformula.updatecell(row, column, curv, false).data; //update formula value
    } else {
      if (value.ct != null) {
        curv.ct = value.ct;
      }
      if (value.f != null) {
        curv.f = value.f;
      }
      if (value.v != null) {
        curv.v = value.v;
      } else {
        curv.v = cell.v;
      }
      if (value.m != null) {
        curv.m = value.m;
      }
      formula.delFunctionGroup(row, column);
      setcellvalue(row, column, data, curv); //update text value
    }
    for (let attr in value) {
      let v = value[attr];
      if (attr in formatList) {
        menuButton.updateFormatCell(data, attr, v, row, row, column, column); //change range format
      } else {
        cell[attr] = v;
      }
    }
    data[row][column] = cell;
  } else {
    if (
      value.toString().substr(0, 1) == "=" ||
      value.toString().substr(0, 5) == "<span"
    ) {
      data = luckysheetformula.updatecell(row, column, value, false).data; //update formula value or convert inline string html to object
    } else {
      formula.delFunctionGroup(row, column);
      setcellvalue(row, column, data, value);
    }
  }

  /* cell更新后触发  */
  setTimeout(() => {
    // Hook function
    method.createHookFunction(
      "cellUpdated",
      row,
      column,
      JSON.parse(oldValue),
      Store.flowdata[row][column],
      isRefresh
    );
  }, 0);

  if (file.index == Store.currentSheetIndex && isRefresh) {
    jfrefreshgrid(data, [{ row: [row, row], column: [column, column] }]); //update data, meanwhile refresh canvas and store data to history
  } else {
    file.data = data; //only update data
  }

  if (success && typeof success === "function") {
    success(data);
  }
}

/**
 * 清除指定工作表指定单元格的内容，返回清除掉的数据，不同于删除单元格的功能，不需要设定单元格移动情况
 * @param {Number} row 单元格所在行数；从0开始的整数，0表示第一行
 * @param {Number} column 单元格所在列数；从0开始的整数，0表示第一列
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function clearCell(row, column, options = {}) {
  if (!isRealNum(row) || !isRealNum(column)) {
    return tooltip.info(
      "Arguments row and column cannot be null or undefined.",
      ""
    );
  }

  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let { order = curSheetOrder, success } = { ...options };

  let targetSheetData = $.extend(true, [], Store.luckysheetfile[order].data);
  let cell = targetSheetData[row][column];

  if (getObjType(cell) == "object") {
    delete cell["m"];
    delete cell["v"];

    if (cell["f"] != null) {
      delete cell["f"];
      formula.delFunctionGroup(row, column, order);

      delete cell["spl"];
    }
  } else {
    cell = null;
  }

  // 若操作为当前sheet页，则刷新当前sheet页
  if (order === curSheetOrder) {
    jfrefreshgrid(targetSheetData, [
      {
        row: [row, row],
        column: [column, column],
      },
    ]);
  } else {
    Store.luckysheetfile[order].data = targetSheetData;
  }

  if (success && typeof success === "function") {
    success(cell);
  }
}

/**
 * 删除指定工作表指定单元格，返回删除掉的数据，同时，指定是右侧单元格左移还是下方单元格上移
 * @param {String} move 删除后，右侧还是下方的单元格移动。可选值为 'left'、'up'
 * @param {Number} row 单元格所在行数；从0开始的整数，0表示第一行
 * @param {Number} column 单元格所在列数；从0开始的整数，0表示第一列
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function deleteCell(move, row, column, options = {}) {
  let moveTypes = ["left", "up"];
  if (!move || moveTypes.indexOf(move) < 0) {
    return tooltip.info(
      "Arguments move cannot be null or undefined and its value must be 'left' or 'up'",
      ""
    );
  }

  if (!isRealNum(row) || !isRealNum(column)) {
    return tooltip.info(
      "Arguments row and column cannot be null or undefined.",
      ""
    );
  }

  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let { order = curSheetOrder, success } = { ...options };

  let moveType = "move" + move.replace(move[0], move[0].toUpperCase()); // left-moveLeft;  up-moveUp

  let sheetIndex;
  if (order) {
    if (Store.luckysheetfile[order]) {
      sheetIndex = Store.luckysheetfile[order].index;
    }
  }

  luckysheetDeleteCell(moveType, row, row, column, column, sheetIndex);

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 设置某个单元格的属性，如果要设置单元格的值或者同时设置多个单元格属性，推荐使用setCellValue
 * @param {Number} row 单元格所在行数；从0开始的整数，0表示第一行
 * @param {Number} column 单元格所在列数；从0开始的整数，0表示第一列
 * @param {String} attr
 * @param {Number | String | Object} value 具体的设置值，一个属性会对应多个值，参考 单元格属性表的值示例，特殊情况：如果属性类型attr是单元格格式ct，则设置值value应提供ct.fa，比如设置A1单元格的格式为百分比格式：luckysheet.setCellFormat(0, 0, "ct", "0.00%")
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数, callback参数为改变后的cell对象
 */
export function setCellFormat(row, column, attr, value, options = {}) {
  if (!isRealNum(row) || !isRealNum(column)) {
    return tooltip.info(
      "Arguments row or column cannot be null or undefined.",
      ""
    );
  }

  if (!attr) {
    return tooltip.info("Arguments attr cannot be null or undefined.", "");
  }

  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let { order = curSheetOrder, success } = { ...options };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  let targetSheetData = $.extend(true, [], file.data);
  if (targetSheetData.length == 0) {
    targetSheetData = sheetmanage.buildGridData(file);
  }

  let cellData = targetSheetData[row][column] || {};
  let cfg = $.extend(true, {}, file.config);

  // 特殊格式
  if (
    attr == "ct" &&
    (!value || !value.hasOwnProperty("fa") || !value.hasOwnProperty("t"))
  ) {
    return new TypeError(
      "While set attribute 'ct' to cell, the value must have property 'fa' and 't'"
    );
  }

  if (attr == "bd") {
    if (cfg["borderInfo"] == null) {
      cfg["borderInfo"] = [];
    }

    let borderInfo = {
      rangeType: "range",
      borderType: "border-all",
      color: "#000",
      style: "1",
      range: [
        {
          column: [column, column],
          row: [row, row],
        },
      ],
      ...value,
    };

    cfg["borderInfo"].push(borderInfo);
  } else {
    cellData[attr] = value;
  }

  targetSheetData[row][column] = cellData;

  // refresh
  if (file.index == Store.currentSheetIndex) {
    file.config = cfg;
    Store.config = cfg;
    jfrefreshgrid(targetSheetData, [
      { row: [row, row], column: [column, column] },
    ]);
  } else {
    file.config = cfg;
    file.data = targetSheetData;
  }

  if (success && typeof success === "function") {
    success(cellData);
  }
}

/**
 * 查找一个工作表中的指定内容，返回查找到的内容组成的单元格一位数组，数据格式同celldata
 * @param {String} content 要查找的内容 可以为正则表达式（不包含前后'/')
 * @param {Object} options 可选参数
 * @param {Boolean} options.isRegularExpression 是否正则表达式匹配；默认为 false. 注意：正则中的规则需要转义，如\S需要写成 \\S
 * @param {Boolean} options.isWholeWord 是否整词匹配；默认为 false
 * @param {Boolean} options.isCaseSensitive 是否区分大小写匹配；默认为 false
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {String} options.type 单元格属性；默认值为m
 */
export function find(content, options = {}) {
  if (!content && content != 0) {
    return tooltip.info("Search content cannot be null or empty", "");
  }

  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let {
    isRegularExpression = false,
    isWholeWord = false,
    isCaseSensitive = false,
    order = curSheetOrder,
    type = "m",
  } = { ...options };
  let targetSheetData = Store.luckysheetfile[order].data;

  let result = [];
  for (let i = 0; i < targetSheetData.length; i++) {
    const rowArr = targetSheetData[i];

    for (let j = 0; j < rowArr.length; j++) {
      const cell = rowArr[j];

      if (!cell) {
        continue;
      }

      // 添加cell的row, column属性
      // replace方法中的setCellValue中需要使用该属性
      cell.row = i;
      cell.column = j;

      if (isWholeWord) {
        if (isCaseSensitive) {
          if (content.toString() == cell[type]) {
            result.push(cell);
          }
        } else {
          if (
            cell[type] &&
            content.toString().toLowerCase() == cell[type].toLowerCase()
          ) {
            result.push(cell);
          }
        }
      } else if (isRegularExpression) {
        let reg;
        if (isCaseSensitive) {
          reg = new RegExp(func_methods.getRegExpStr(content), "g");
        } else {
          reg = new RegExp(func_methods.getRegExpStr(content), "ig");
        }
        if (reg.test(cell[type])) {
          result.push(cell);
        }
      } else if (isCaseSensitive) {
        let reg = new RegExp(func_methods.getRegExpStr(content), "g");
        if (reg.test(cell[type])) {
          result.push(cell);
        }
      } else {
        let reg = new RegExp(func_methods.getRegExpStr(content), "ig");
        if (reg.test(cell[type])) {
          result.push(cell);
        }
      }
    }
  }

  return result;
}

/**
 * 查找一个工作表中的指定内容并替换成新的内容，返回替换后的内容组成的单元格一位数组，数据格式同celldata。
 * @param {String} content 要查找的内容
 * @param {String} replaceContent 要替换的内容
 * @param {Object} options 可选参数
 * @param {Boolean} options.isRegularExpression 是否正则表达式匹配；默认为 false
 * @param {Boolean} options.isWholeWord 是否整词匹配；默认为 false
 * @param {Boolean} options.isCaseSensitive 是否区分大小写匹配；默认为 false
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数, callback参数为替换后的cell集合
 */
export function replace(content, replaceContent, options = {}) {
  let matchCells = find(content, options);
  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let { order = curSheetOrder } = { ...options };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }
  let sheetData = $.extend(true, [], file.data);

  matchCells.forEach((cell) => {
    cell.m = replaceContent;
    setCellValue(cell.row, cell.column, replaceContent, {
      order: order,
      isRefresh: false,
    });
  });

  let fileData = $.extend(true, [], file.data);
  file.data.length = 0;
  file.data.push(...sheetData);

  if (file.index == Store.currentSheetIndex) {
    jfrefreshgrid(fileData, undefined, undefined, true, false);
  }

  luckysheetrefreshgrid();

  if (options.success && typeof options.success === "function") {
    options.success(matchCells);
  }
  return matchCells;
}

/**
 * 手动触发退出编辑模式
 * @param {Object} options 可选参数
 * @param {Function} options.success 操作结束的回调函数
 */
export function exitEditMode(options = {}) {
  if (parseInt($("#luckysheet-input-box").css("top")) > 0) {
    if (
      $("#luckysheet-formula-search-c").is(":visible") &&
      formula.searchFunctionCell != null
    ) {
      formula.searchFunctionEnter(
        $("#luckysheet-formula-search-c").find(
          ".luckysheet-formula-search-item-active"
        )
      );
    } else {
      formula.updatecell(
        Store.luckysheetCellUpdate[0],
        Store.luckysheetCellUpdate[1]
      );
      Store.luckysheet_select_save = [
        {
          row: [Store.luckysheetCellUpdate[0], Store.luckysheetCellUpdate[0]],
          column: [
            Store.luckysheetCellUpdate[1],
            Store.luckysheetCellUpdate[1],
          ],
          row_focus: Store.luckysheetCellUpdate[0],
          column_focus: Store.luckysheetCellUpdate[1],
        },
      ];
    }

    //若有参数弹出框，隐藏
    if ($("#luckysheet-search-formula-parm").is(":visible")) {
      $("#luckysheet-search-formula-parm").hide();
    }
    //若有参数选取范围弹出框，隐藏
    if ($("#luckysheet-search-formula-parm-select").is(":visible")) {
      $("#luckysheet-search-formula-parm-select").hide();
    }
  }

  if (options.success && typeof options.success === "function") {
    options.success();
  }
}

/**
 * 手动触发进入编辑模式
 * @param {Object} options 可选参数
 * @param {Function} options.success 操作结束的回调函数
 */
export function enterEditMode(options = {}) {
  if ($("#luckysheet-conditionformat-dialog").is(":visible")) {
    return;
  } else if ($("#luckysheet-cell-selected").is(":visible")) {
    let last =
      Store.luckysheet_select_save[Store.luckysheet_select_save.length - 1];

    let row_index = last["row_focus"],
      col_index = last["column_focus"];

    luckysheetupdateCell(row_index, col_index, Store.flowdata);
  }

  if (options.success && typeof options.success === "function") {
    options.success();
  }
}

/**
 * 冻结首行
 * 若设置冻结的sheet不是当前sheet页，只设置参数不渲染
 * @param {Number | String} order 工作表索引
 */
export function frozenFirstRow(order) {
  // store frozen
  luckysheetFreezen.saveFrozen("freezenRow", order);

  // 冻结为当前sheet页
  if (!order || order == getSheetIndex(Store.currentSheetIndex)) {
    let freezenhorizontaldata, row_st, top;
    if (luckysheetFreezen.freezenRealFirstRowColumn) {
      let row_st = 0;
      top = Store.visibledatarow[row_st] - 2 + Store.columnHeaderHeight;
      freezenhorizontaldata = [
        Store.visibledatarow[row_st],
        row_st + 1,
        0,
        luckysheetFreezen.cutVolumn(Store.visibledatarow, row_st + 1),
        top,
      ];
    } else {
      let scrollTop = $("#luckysheet-cell-main").scrollTop();
      row_st = luckysheet_searcharray(Store.visibledatarow, scrollTop);
      if (row_st == -1) {
        row_st = 0;
      }

      top =
        Store.visibledatarow[row_st] - 2 - scrollTop + Store.columnHeaderHeight;
      freezenhorizontaldata = [
        Store.visibledatarow[row_st],
        row_st + 1,
        scrollTop,
        luckysheetFreezen.cutVolumn(Store.visibledatarow, row_st + 1),
        top,
      ];
    }

    luckysheetFreezen.saveFreezen(freezenhorizontaldata, top, null, null);

    if (luckysheetFreezen.freezenverticaldata != null) {
      luckysheetFreezen.cancelFreezenVertical();
      luckysheetFreezen.createAssistCanvas();
      luckysheetrefreshgrid();
    }

    luckysheetFreezen.createFreezenHorizontal(freezenhorizontaldata, top);
    luckysheetFreezen.createAssistCanvas();
    luckysheetrefreshgrid();
  }
}

/**
 * 冻结首列
 * 若设置冻结的sheet不是当前sheet页，只设置参数不渲染
 * @param {Number | String} order 工作表索引
 */
export function frozenFirstColumn(order) {
  // store frozen
  luckysheetFreezen.saveFrozen("freezenColumn", order);

  // 冻结为当前sheet页
  if (!order || order == getSheetIndex(Store.currentSheetIndex)) {
    let freezenverticaldata, col_st, left;
    if (luckysheetFreezen.freezenRealFirstRowColumn) {
      col_st = 0;
      left = Store.visibledatacolumn[col_st] - 2 + Store.rowHeaderWidth;
      freezenverticaldata = [
        Store.visibledatacolumn[col_st],
        col_st + 1,
        0,
        luckysheetFreezen.cutVolumn(Store.visibledatacolumn, col_st + 1),
        left,
      ];
    } else {
      let scrollLeft = $("#luckysheet-cell-main").scrollLeft();

      col_st = luckysheet_searcharray(Store.visibledatacolumn, scrollLeft);
      if (col_st == -1) {
        col_st = 0;
      }

      left =
        Store.visibledatacolumn[col_st] - 2 - scrollLeft + Store.rowHeaderWidth;
      freezenverticaldata = [
        Store.visibledatacolumn[col_st],
        col_st + 1,
        scrollLeft,
        luckysheetFreezen.cutVolumn(Store.visibledatacolumn, col_st + 1),
        left,
      ];
    }

    luckysheetFreezen.saveFreezen(null, null, freezenverticaldata, left);

    if (luckysheetFreezen.freezenhorizontaldata != null) {
      luckysheetFreezen.cancelFreezenHorizontal();
      luckysheetFreezen.createAssistCanvas();
      luckysheetrefreshgrid();
    }

    luckysheetFreezen.createFreezenVertical(freezenverticaldata, left);
    luckysheetFreezen.createAssistCanvas();
    luckysheetrefreshgrid();
  }
}

/**
 * 冻结行选区
 * @param {Object} range 行选区范围的focus单元格的行列值构成的对象；格式为{ row_focus:0, column_focus:0 }
 * @param {Number | String} order 工作表索引
 */
export function frozenRowRange(range, order) {
  const locale_frozen = locale().freezen;

  if (
    !range ||
    (!range.hasOwnProperty("row_focus") && !formula.iscelldata(range))
  ) {
    if (isEditMode()) {
      alert(locale_frozen.noSeletionError);
    } else {
      tooltip.info(locale_frozen.noSeletionError, "");
    }
    return;
  }

  if (typeof range === "string" && formula.iscelldata(range)) {
    range = formula.getcellrange(range);
    range = {
      row_focus: range.row[0],
      column_focus: range.column[0],
    };
  }
  // store frozen
  luckysheetFreezen.saveFrozen("freezenRowRange", order, range);

  if (!order || order == getSheetIndex(Store.currentSheetIndex)) {
    let scrollTop = $("#luckysheet-cell-main").scrollTop();
    let row_st = luckysheet_searcharray(Store.visibledatarow, scrollTop);

    let row_focus = range.row_focus;
    if (row_focus > row_st) {
      row_st = row_focus;
    }
    if (row_st == -1) {
      row_st = 0;
    }

    let top =
      Store.visibledatarow[row_st] - 2 - scrollTop + Store.columnHeaderHeight;
    let freezenhorizontaldata = [
      Store.visibledatarow[row_st],
      row_st + 1,
      scrollTop,
      luckysheetFreezen.cutVolumn(Store.visibledatarow, row_st + 1),
      top,
    ];
    luckysheetFreezen.saveFreezen(freezenhorizontaldata, top, null, null);

    if (luckysheetFreezen.freezenverticaldata != null) {
      luckysheetFreezen.cancelFreezenVertical();
      luckysheetFreezen.createAssistCanvas();
      luckysheetrefreshgrid();
    }

    luckysheetFreezen.createFreezenHorizontal(freezenhorizontaldata, top);
    luckysheetFreezen.createAssistCanvas();
    luckysheetrefreshgrid();
  }
}

/**
 * 冻结列选区
 * @param {Object} range 列选区范围的focus单元格的行列值构成的对象；格式为{ row_focus:0, column_focus:0 }
 * @param {Number | String} order 工作表索引
 */
export function frozenColumnRange(range, order) {
  const locale_frozen = locale().freezen;
  let isStringRange = typeof range === "string" && formula.iscelldata(range);

  if (!range || (!range.hasOwnProperty("column_focus") && !isStringRange)) {
    if (isEditMode()) {
      alert(locale_frozen.noSeletionError);
    } else {
      tooltip.info(locale_frozen.noSeletionError, "");
    }
    return;
  }

  if (isStringRange) {
    range = formula.getcellrange(range);
    range = {
      row_focus: range.row[0],
      column_focus: range.column[0],
    };
  }
  // store frozen
  luckysheetFreezen.saveFrozen("freezenColumnRange", order, range);

  if (!order || order == getSheetIndex(Store.currentSheetIndex)) {
    let scrollLeft = $("#luckysheet-cell-main").scrollLeft();
    let col_st = luckysheet_searcharray(Store.visibledatacolumn, scrollLeft);

    let column_focus = range.column_focus;
    if (column_focus > col_st) {
      col_st = column_focus;
    }
    if (col_st == -1) {
      col_st = 0;
    }

    let left =
      Store.visibledatacolumn[col_st] - 2 - scrollLeft + Store.rowHeaderWidth;
    let freezenverticaldata = [
      Store.visibledatacolumn[col_st],
      col_st + 1,
      scrollLeft,
      luckysheetFreezen.cutVolumn(Store.visibledatacolumn, col_st + 1),
      left,
    ];
    luckysheetFreezen.saveFreezen(null, null, freezenverticaldata, left);

    if (luckysheetFreezen.freezenhorizontaldata != null) {
      luckysheetFreezen.cancelFreezenHorizontal();
      luckysheetFreezen.createAssistCanvas();
      luckysheetrefreshgrid();
    }

    luckysheetFreezen.createFreezenVertical(freezenverticaldata, left);
    luckysheetFreezen.createAssistCanvas();
    luckysheetrefreshgrid();
  }
}

/**
 * 取消冻结
 * @param {Number | String} order
 */
export function cancelFrozen(order) {
  luckysheetFreezen.saveFrozen("freezenCancel", order);

  // 取消当前sheet冻结时，刷新canvas
  if (!order || order == getSheetIndex(Store.currentSheetIndex)) {
    if (luckysheetFreezen.freezenverticaldata != null) {
      luckysheetFreezen.cancelFreezenVertical();
    }
    if (luckysheetFreezen.freezenhorizontaldata != null) {
      luckysheetFreezen.cancelFreezenHorizontal();
    }
    luckysheetFreezen.createAssistCanvas();
    luckysheetrefreshgrid();
  }
}

/**
 * 冻结行操作。特别注意，只有在isRange设置为true的时候，才需要设置setting中的range，且与一般的range格式不同。
 * @param {Boolean} isRange 是否冻结行到选区 true-冻结行到选区  false-冻结首行
 * @param {Object} options 可选参数
 * @param {Object} options.range isRange为true的时候设置，开启冻结的单元格位置，格式为{ row_focus:0, column_focus:0 }，意为当前激活的单元格的行数和列数；默认从当前选区最后的一个选区中取得
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function setHorizontalFrozen(isRange, options = {}) {
  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let { range, order = curSheetOrder, success } = { ...options };

  // 若已存在冻结，取消之前的冻结效果
  cancelFrozen(order);

  if (!isRange) {
    frozenFirstRow(order);
  } else {
    // 选区行冻结
    frozenRowRange(range, order);
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 冻结列操作。特别注意，只有在isRange设置为true的时候，才需要设置setting中的range，且与一般的range格式不同。
 * @param {Boolean} isRange 是否冻结列到选区 true-冻结列到选区  false-冻结首列
 * @param {Object} options 可选参数
 * @param {Object} options.range isRange为true的时候设置，开启冻结的单元格位置，格式为{ row_focus:0, column_focus:0 }，意为当前激活的单元格的行数和列数；默认从当前选区最后的一个选区中取得
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function setVerticalFrozen(isRange, options = {}) {
  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let { range, order = curSheetOrder, success } = { ...options };

  // 若已存在冻结，取消之前的冻结效果
  cancelFrozen(order);

  if (!isRange) {
    frozenFirstColumn(order);
  } else {
    frozenColumnRange(range, order);
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 冻结行列操作。特别注意，只有在isRange设置为true的时候，才需要设置setting中的range，且与一般的range格式不同。
 * @param {Boolean} isRange 是否冻结行列到选区 true-冻结行列到选区  false-冻结首行列
 * @param {Object} options 可选参数
 * @param {Object} options.range isRange为true的时候设置，开启冻结的单元格位置，格式为{ row_focus:0, column_focus:0 }，意为当前激活的单元格的行数和列数；默认从当前选区最后的一个选区中取得
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function setBothFrozen(isRange, options = {}) {
  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let { range, order = curSheetOrder, success } = { ...options };

  let isCurrentSheet =
    !order || order == getSheetIndex(Store.currentSheetIndex);
  const locale_frozen = locale().freezen;

  // 若已存在冻结，取消之前的冻结效果
  cancelFrozen(order);

  // 冻结首行列
  if (!isRange) {
    // store frozen
    luckysheetFreezen.saveFrozen("freezenRC", order);

    if (isCurrentSheet) {
      let scrollTop = $("#luckysheet-cell-main").scrollTop();
      let row_st = luckysheet_searcharray(Store.visibledatarow, scrollTop);
      if (row_st == -1) {
        row_st = 0;
      }
      let top =
        Store.visibledatarow[row_st] - 2 - scrollTop + Store.columnHeaderHeight;
      let freezenhorizontaldata = [
        Store.visibledatarow[row_st],
        row_st + 1,
        scrollTop,
        luckysheetFreezen.cutVolumn(Store.visibledatarow, row_st + 1),
        top,
      ];
      luckysheetFreezen.saveFreezen(freezenhorizontaldata, top, null, null);

      luckysheetFreezen.createFreezenHorizontal(freezenhorizontaldata, top);

      let scrollLeft = $("#luckysheet-cell-main").scrollLeft();
      let col_st = luckysheet_searcharray(Store.visibledatacolumn, scrollLeft);
      if (col_st == -1) {
        col_st = 0;
      }
      let left =
        Store.visibledatacolumn[col_st] - 2 - scrollLeft + Store.rowHeaderWidth;
      let freezenverticaldata = [
        Store.visibledatacolumn[col_st],
        col_st + 1,
        scrollLeft,
        luckysheetFreezen.cutVolumn(Store.visibledatacolumn, col_st + 1),
        left,
      ];
      luckysheetFreezen.saveFreezen(null, null, freezenverticaldata, left);

      luckysheetFreezen.createFreezenVertical(freezenverticaldata, left);

      luckysheetFreezen.createAssistCanvas();
      luckysheetrefreshgrid();
    }
  } else {
    // 冻结行列到选区
    // store frozen
    luckysheetFreezen.saveFrozen("freezenRCRange", order, range);

    let isStringRange = typeof range === "string" && formula.iscelldata(range);
    if (isCurrentSheet) {
      if (
        (!range ||
          !(
            range.hasOwnProperty("column_focus") &&
            range.hasOwnProperty("row_focus")
          )) &&
        !isStringRange
      ) {
        if (isEditMode()) {
          alert(locale_frozen.noSeletionError);
        } else {
          tooltip.info(locale_frozen.noSeletionError, "");
        }
        return;
      }

      if (isStringRange) {
        range = formula.getcellrange(range);
        range = {
          row_focus: range.row[0],
          column_focus: range.column[0],
        };
      }

      let scrollTop = $("#luckysheet-cell-main").scrollTop();
      let row_st = luckysheet_searcharray(Store.visibledatarow, scrollTop);

      let row_focus = range.row_focus;

      if (row_focus > row_st) {
        row_st = row_focus;
      }

      if (row_st == -1) {
        row_st = 0;
      }

      let top =
        Store.visibledatarow[row_st] - 2 - scrollTop + Store.columnHeaderHeight;
      let freezenhorizontaldata = [
        Store.visibledatarow[row_st],
        row_st + 1,
        scrollTop,
        luckysheetFreezen.cutVolumn(Store.visibledatarow, row_st + 1),
        top,
      ];
      luckysheetFreezen.saveFreezen(freezenhorizontaldata, top, null, null);

      luckysheetFreezen.createFreezenHorizontal(freezenhorizontaldata, top);

      let scrollLeft = $("#luckysheet-cell-main").scrollLeft();
      let col_st = luckysheet_searcharray(Store.visibledatacolumn, scrollLeft);

      let column_focus = range.column_focus;

      if (column_focus > col_st) {
        col_st = column_focus;
      }

      if (col_st == -1) {
        col_st = 0;
      }

      let left =
        Store.visibledatacolumn[col_st] - 2 - scrollLeft + Store.rowHeaderWidth;
      let freezenverticaldata = [
        Store.visibledatacolumn[col_st],
        col_st + 1,
        scrollLeft,
        luckysheetFreezen.cutVolumn(Store.visibledatacolumn, col_st + 1),
        left,
      ];
      luckysheetFreezen.saveFreezen(null, null, freezenverticaldata, left);

      luckysheetFreezen.createFreezenVertical(freezenverticaldata, left);

      luckysheetFreezen.createAssistCanvas();
      luckysheetrefreshgrid();
    }
  }
}

/**
 * 在第index行或列的位置，插入number行或列
 * @param {String} type 插入行或列 row-行  column-列
 * @param {Number} index 在第几行插入空白行，从0开始
 * @param {Object} options 可选参数
 * @param {Number} options.number 插入的空白行数；默认为 1
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function insertRowOrColumn(type, index = 0, options = {}) {
  if (!isRealNum(index)) {
    return tooltip.info("The index parameter is invalid.", "");
  }

  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let { number = 1, order = curSheetOrder, success } = { ...options };

  let _locale = locale();
  let locale_info = _locale.info;
  if (!isRealNum(number)) {
    if (isEditMode()) {
      alert(locale_info.tipInputNumber);
    } else {
      tooltip.info(locale_info.tipInputNumber, "");
    }
    return;
  }

  number = parseInt(number);
  if (number < 1 || number > 100) {
    if (isEditMode()) {
      alert(locale_info.tipInputNumberLimit);
    } else {
      tooltip.info(locale_info.tipInputNumberLimit, "");
    }
    return;
  }

  // 默认在行上方增加行，列左侧增加列
  let sheetIndex;
  if (order) {
    if (Store.luckysheetfile[order]) {
      sheetIndex = Store.luckysheetfile[order].index;
    }
  }

  luckysheetextendtable(type, index, number, "lefttop", sheetIndex);

  if (success && typeof success === "function") {
    success();
  }
}
/**
 * 在第index行或列的位置，插入number行或列
 * @param {String} type 插入行或列 row-行  column-列
 * @param {Number} index 在第几行插入空白行，从0开始
 * @param {Object} options 可选参数
 * @param {Number} options.number 插入的空白行数；默认为 1
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function insertRowBottomOrColumnRight(type, index = 0, options = {}) {
  if (!isRealNum(index)) {
    return tooltip.info("The index parameter is invalid.", "");
  }

  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let { number = 1, order = curSheetOrder, success } = { ...options };

  let _locale = locale();
  let locale_info = _locale.info;
  if (!isRealNum(number)) {
    if (isEditMode()) {
      alert(locale_info.tipInputNumber);
    } else {
      tooltip.info(locale_info.tipInputNumber, "");
    }
    return;
  }

  number = parseInt(number);
  if (number < 1 || number > 100) {
    if (isEditMode()) {
      alert(locale_info.tipInputNumberLimit);
    } else {
      tooltip.info(locale_info.tipInputNumberLimit, "");
    }
    return;
  }

  // 默认在行上方增加行，列左侧增加列
  let sheetIndex;
  if (order) {
    if (Store.luckysheetfile[order]) {
      sheetIndex = Store.luckysheetfile[order].index;
    }
  }

  luckysheetextendtable(type, index, number, "rightbottom", sheetIndex);

  if (success && typeof success === "function") {
    success();
  }
}
/**
 * 在第row行的位置，插入number行空白行
 * @param {Number} row 在第几行插入空白行，从0开始
 * @param {Object} options 可选参数
 * @param {Number} options.number 插入的空白行数；默认为 1
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function insertRow(row = 0, options = {}) {
  insertRowOrColumn("row", row, options);
}
/**
 * 在第row行的位置，插入number行空白行
 * @param {Number} row 在第几行插入空白行，从0开始
 * @param {Object} options 可选参数
 * @param {Number} options.number 插入的空白行数；默认为 1
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function insertRowBottom(row = 0, options = {}) {
  insertRowBottomOrColumnRight("row", row, options);
}
/**
 * 在第column列的位置，插入number列空白列
 * @param {Number} column 在第几列插入空白列，从0开始
 * @param {Object} options 可选参数
 * @param {Number} options.number 插入的空白列数；默认为 1
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function insertColumn(column = 0, options = {}) {
  insertRowOrColumn("column", column, options);
}
/**
 * 在第column列的位置，插入number列空白列
 * @param {Number} column 在第几列插入空白列，从0开始
 * @param {Object} options 可选参数
 * @param {Number} options.number 插入的空白列数；默认为 1
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function insertColumnRight(column = 0, options = {}) {
  insertRowBottomOrColumnRight("column", column, options);
}
/**
 * 删除指定的行或列。删除行列之后，行列的序号并不会变化，下面的行（右侧的列）会补充到上（左）面，注意观察数据是否被正确删除即可。
 * @param {String} type 删除行或列 row-行  column-列
 * @param {Number} startIndex 要删除的起始行或列
 * @param {Number} endIndex 要删除的结束行或列
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function deleteRowOrColumn(type, startIndex, endIndex, options = {}) {
  if (!isRealNum(startIndex) || !isRealNum(endIndex)) {
    return tooltip.info(
      "Please enter the index for deleting rows or columns correctly.",
      ""
    );
  }

  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let { order = curSheetOrder, success } = { ...options };

  let sheetIndex;
  if (order) {
    if (Store.luckysheetfile[order]) {
      sheetIndex = Store.luckysheetfile[order].index;
    }
  }
  luckysheetdeletetable(type, startIndex, endIndex, sheetIndex);

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 删除指定的行。
 * @param {Number} rowStart 要删除的起始行
 * @param {Number} rowEnd 要删除的结束行
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function deleteRow(rowStart, rowEnd, options = {}) {
  deleteRowOrColumn("row", rowStart, rowEnd, options);
}

/**
 * 删除指定的列。
 * @param {Number} columnStart 要删除的起始列
 * @param {Number} columnEnd 要删除的结束列
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function deleteColumn(columnStart, columnEnd, options = {}) {
  deleteRowOrColumn("column", columnStart, columnEnd, options);
}

/**
 * 隐藏行或列
 * @param {String} type 隐藏行或列  row-隐藏行  column-隐藏列
 * @param {Number} startIndex 起始行或列
 * @param {Number} endIndex 结束行或列
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function hideRowOrColumn(type, startIndex, endIndex, options = {}) {
  if (!isRealNum(startIndex) || !isRealNum(endIndex)) {
    return tooltip.info(
      "Please enter the index for deleting rows or columns correctly.",
      ""
    );
  }

  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let { order = curSheetOrder, saveParam = true, success } = { ...options };

  let file = Store.luckysheetfile[order];
  let cfgKey = type === "row" ? "rowhidden" : "colhidden";
  let cfg = $.extend(true, {}, file.config);
  if (cfg[cfgKey] == null) {
    cfg[cfgKey] = {};
  }

  for (let i = startIndex; i <= endIndex; i++) {
    cfg[cfgKey][i] = 0;
  }

  //保存撤销
  if (Store.clearjfundo) {
    let redo = {};
    redo["type"] = type === "row" ? "showHidRows" : "showHidCols";
    redo["sheetIndex"] = file.index;
    redo["config"] = $.extend(true, {}, file.config);
    redo["curconfig"] = cfg;

    Store.jfundo.length = 0;
    Store.jfredo.push(redo);
  }

  Store.luckysheetfile[order].config = cfg;

  if (saveParam) {
    server.saveParam("cg", file.index, cfg[cfgKey], { k: cfgKey });
  }

  // 若操作sheet为当前sheet页，行高、列宽 刷新
  if (order == curSheetOrder) {
    //config
    Store.config = cfg;
    jfrefreshgrid_rhcw(Store.flowdata.length, Store.flowdata[0].length);
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 显示隐藏的行或列
 * @param {String} type 显示行或列  row-显示行  column-显示列
 * @param {Number} startIndex 起始行或列
 * @param {Number} endIndex 结束行或列
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function showRowOrColumn(type, startIndex, endIndex, options = {}) {
  if (!isRealNum(startIndex) || !isRealNum(endIndex)) {
    return tooltip.info(
      "Please enter the index for deleting rows or columns correctly.",
      ""
    );
  }

  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let { order = curSheetOrder, saveParam = true, success } = { ...options };

  let file = Store.luckysheetfile[order];
  let cfgKey = type === "row" ? "rowhidden" : "colhidden";
  let cfg = $.extend(true, {}, file.config);
  if (cfg[cfgKey] == null) {
    return;
  }

  for (let i = startIndex; i <= endIndex; i++) {
    delete cfg[cfgKey][i];
  }

  //保存撤销
  if (Store.clearjfundo) {
    let redo = {};
    redo["type"] = type === "row" ? "showHidRows" : "showHidCols";
    redo["sheetIndex"] = file.index;
    redo["config"] = $.extend(true, {}, file.config);
    redo["curconfig"] = cfg;

    Store.jfundo.length = 0;
    Store.jfredo.push(redo);
  }

  //config
  Store.luckysheetfile[order].config = Store.config;

  if (saveParam) {
    server.saveParam("cg", file.index, cfg[cfgKey], { k: cfgKey });
  }

  // 若操作sheet为当前sheet页，行高、列宽 刷新
  if (order === curSheetOrder) {
    Store.config = cfg;
    jfrefreshgrid_rhcw(Store.flowdata.length, Store.flowdata[0].length);
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 隐藏行
 * @param {Number} startIndex 起始行
 * @param {Number} endIndex 结束行
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function hideRow(startIndex, endIndex, options = {}) {
  hideRowOrColumn("row", startIndex, endIndex, options);
}

/**
 * 显示行
 * @param {Number} startIndex 起始行
 * @param {Number} endIndex 结束行
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function showRow(startIndex, endIndex, options = {}) {
  showRowOrColumn("row", startIndex, endIndex, options);
}

/**
 * 隐藏列
 * @param {Number} startIndex 起始列
 * @param {Number} endIndex 结束列
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function hideColumn(startIndex, endIndex, options = {}) {
  hideRowOrColumn("column", startIndex, endIndex, options);
}

/**
 * 显示列
 * @param {Number} startIndex 起始列
 * @param {Number} endIndex 结束列
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function showColumn(startIndex, endIndex, options = {}) {
  showRowOrColumn("column", startIndex, endIndex, options);
}

/**
 * 设置指定行的高度。优先级最高，高于默认行高和用户自定义行高。
 * @param {Object} rowInfo 行数和高度对应关系
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function setRowHeight(rowInfo, options = {}) {
  if (getObjType(rowInfo) != "object") {
    return tooltip.info("The rowInfo parameter is invalid.", "");
  }

  let { order = getSheetIndex(Store.currentSheetIndex), success } = {
    ...options,
  };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  let cfg = $.extend(true, {}, file.config);
  if (cfg["rowlen"] == null) {
    cfg["rowlen"] = {};
  }

  for (let r in rowInfo) {
    if (parseInt(r) >= 0) {
      let len = rowInfo[r];

      if (len === "auto") {
        cfg["rowlen"][parseInt(r)] = len;
      } else {
        if (Number(len) >= 0) {
          cfg["rowlen"][parseInt(r)] = Number(len);
        }
      }
    }
  }

  file.config = cfg;

  server.saveParam("cg", file.index, cfg["rowlen"], { k: "rowlen" });

  if (file.index == Store.currentSheetIndex) {
    Store.config = cfg;
    jfrefreshgrid_rhcw(Store.flowdata.length, Store.flowdata[0].length);
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 设置指定列的宽度
 * @param {Object} columnInfo 行数和高度对应关系
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function setColumnWidth(columnInfo, options = {}) {
  if (getObjType(columnInfo) != "object") {
    return tooltip.info("The columnInfo parameter is invalid.", "");
  }

  let { order = getSheetIndex(Store.currentSheetIndex), success } = {
    ...options,
  };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  let cfg = $.extend(true, {}, file.config);
  if (cfg["columnlen"] == null) {
    cfg["columnlen"] = {};
  }

  for (let c in columnInfo) {
    if (parseInt(c) >= 0) {
      let len = columnInfo[c];

      if (len === "auto") {
        cfg["columnlen"][parseInt(c)] = len;
      } else {
        if (Number(len) >= 0) {
          cfg["columnlen"][parseInt(c)] = Number(len);
        }
      }
    }
  }

  file.config = cfg;

  server.saveParam("cg", file.index, cfg["columnlen"], { k: "columnlen" });

  if (file.index == Store.currentSheetIndex) {
    Store.config = cfg;
    jfrefreshgrid_rhcw(Store.flowdata.length, Store.flowdata[0].length);
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 获取指定工作表指定行的高度，得到行号和高度对应关系的对象
 * @param {Array} rowInfo 行号下标组成的数组；行号下标从0开始；
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function getRowHeight(rowInfo, options = {}) {
  if (getObjType(rowInfo) != "array" || rowInfo.length == 0) {
    return tooltip.info("The rowInfo parameter is invalid.", "");
  }

  let { order = getSheetIndex(Store.currentSheetIndex), success } = {
    ...options,
  };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  let cfg = $.extend(true, {}, file.config);
  let rowlen = cfg["rowlen"] || {};

  let rowlenObj = {};

  rowInfo.forEach((item) => {
    if (parseInt(item) >= 0) {
      let size = rowlen[parseInt(item)] || Store.defaultrowlen;
      rowlenObj[parseInt(item)] = size;
    }
  });

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 1);

  return rowlenObj;
}

/**
 * 获取指定工作表指定列的宽度，得到列号和宽度对应关系的对象
 * @param {Array} columnInfo 行号下标组成的数组；行号下标从0开始；
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function getColumnWidth(columnInfo, options = {}) {
  if (getObjType(columnInfo) != "array" || columnInfo.length == 0) {
    return tooltip.info("The columnInfo parameter is invalid.", "");
  }

  let { order = getSheetIndex(Store.currentSheetIndex), success } = {
    ...options,
  };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  let cfg = $.extend(true, {}, file.config);
  let columnlen = cfg["columnlen"] || {};

  let columnlenObj = {};

  columnInfo.forEach((item) => {
    if (parseInt(item) >= 0) {
      let size = columnlen[parseInt(item)] || Store.defaultcollen;
      columnlenObj[parseInt(item)] = size;
    }
  });

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 1);

  return columnlenObj;
}

/**
 * 获取工作表的默认行高
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function getDefaultRowHeight(options = {}) {
  let { order = getSheetIndex(Store.currentSheetIndex), success } = {
    ...options,
  };

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 1);

  // *返回指定的工作表默认行高，如果未配置就返回全局的默认行高
  return Store.luckysheetfile[order].defaultRowHeight || Store.defaultrowlen;
}

/**
 * 获取工作表的默认列宽
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function getDefaultColWidth(options = {}) {
  let { order = getSheetIndex(Store.currentSheetIndex), success } = {
    ...options,
  };

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 1);

  // *返回指定的工作表默认列宽，如果未配置就返回全局的默认列宽
  return Store.luckysheetfile[order].defaultColWidth || Store.defaultcollen;
}

/**
 * 返回当前选区对象的数组，可能存在多个选区。
 * 每个选区的格式为row/column信息组成的对象{row:[0,1],column:[0,1]}
 * @returns {Array}
 */
export function getRange() {
  let rangeArr = JSON.parse(JSON.stringify(Store.luckysheet_select_save));

  let result = [];

  for (let i = 0; i < rangeArr.length; i++) {
    let rangeItem = rangeArr[i];
    let temp = {
      row: rangeItem.row,
      column: rangeItem.column,
    };
    result.push(temp);
  }

  return result;
}

/**
 * 返回表示指定区域内所有单元格位置的数组，区别getRange方法，该方法以cell单元格(而非某块连续的区域)为单位来组织选区的数据
 * @param   {Array}   range 可选参数，默认为当前选中区域
 * @returns {Array}   对象数组
 */
export function getRangeWithFlatten(range) {
  range = range || getRange();

  let result = [];

  range.forEach((ele) => {
    // 这个data可能是个范围或者是单个cell
    let rs = ele.row;
    let cs = ele.column;
    for (let r = rs[0]; r <= rs[1]; r++) {
      for (let c = cs[0]; c <= cs[1]; c++) {
        // r c 当前的r和当前的c
        result.push({ r, c });
      }
    }
  });
  return result;
}

/**
 * 返回表示指定区域内所有单元格内容的对象数组
 * @param   {Array}   range 可选参数，默认为当前选中区域扁平化后的对象，结构形如[{r:0,c:0},{r:0,c:1}...]
 * @returns {Array}   对象数组
 */
export function getRangeValuesWithFlatte(range) {
  range = range || getRangeWithFlatten();

  let values = [];

  // 获取到的这个数据不是最新的数据
  range.forEach((item) => {
    values.push(Store.flowdata[item.r][item.c]);
  });
  return values;
}

/**
 * 返回对应当前选区的坐标字符串数组，可能存在多个选区。
 * 每个选区可能是单个单元格(如 A1)或多个单元格组成的矩形区域(如 D9:E12)
 * @returns {Array}
 */
export function getRangeAxis() {
  let result = [];
  let rangeArr = JSON.parse(JSON.stringify(Store.luckysheet_select_save));
  let sheetIndex = Store.currentSheetIndex;

  rangeArr.forEach((ele) => {
    let axisText = getRangetxt(sheetIndex, {
      column: ele.column,
      row: ele.row,
    });
    result.push(axisText);
  });

  return result;
}

/**
 * 返回指定工作表指定范围的单元格二维数组数据，每个单元格为一个对象
 * @param {Object} options 可选参数
 * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]}，只能为单个选区；默认为当前选区
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 */
export function getRangeValue(options = {}) {
  let curOrder = getSheetIndex(Store.currentSheetIndex);
  let { range, order = curOrder } = { ...options };

  let file = Store.luckysheetfile[order];

  if (!range || typeof range === "object") {
    return getdatabyselection(range, file.index);
  } else if (typeof range === "string") {
    if (formula.iscelldata(range)) {
      return getdatabyselection(formula.getcellrange(range), file.index);
    } else {
      tooltip.info("The range is invalid, please check range parameter.", "");
    }
  }
}

/**
 * 复制指定工作表指定单元格区域的数据，返回包含`<table>`html格式的数据，可用于粘贴到excel中保持单元格样式。
 * @param {Object} options 可选参数
 * @param {Array | Object | String} options.range 选区范围
 * @param {order} options.order 工作表下标
 */
export function getRangeHtml(options = {}) {
  let {
    range = Store.luckysheet_select_save,
    order = getSheetIndex(Store.currentSheetIndex),
    success,
  } = { ...options };
  range = JSON.parse(JSON.stringify(range));

  if (getObjType(range) == "string") {
    if (!formula.iscelldata(range)) {
      return tooltip.info("The range parameter is invalid.", "");
    }

    let cellrange = formula.getcellrange(range);
    range = [
      {
        row: cellrange.row,
        column: cellrange.column,
      },
    ];
  } else if (getObjType(range) == "object") {
    if (range.row == null || range.column == null) {
      return tooltip.info("The range parameter is invalid.", "");
    }

    range = [
      {
        row: range.row,
        column: range.column,
      },
    ];
  }

  if (getObjType(range) != "array") {
    return tooltip.info("The range parameter is invalid.", "");
  }

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  //复制范围内包含部分合并单元格，提示
  let cfg = $.extend(true, {}, file.config);
  if (cfg["merge"] != null) {
    let has_PartMC = false;

    for (let s = 0; s < range.length; s++) {
      let r1 = range[s].row[0],
        r2 = range[s].row[1];
      let c1 = range[s].column[0],
        c2 = range[s].column[1];

      has_PartMC = hasPartMC(cfg, r1, r2, c1, c2);

      if (has_PartMC) {
        break;
      }
    }

    if (has_PartMC) {
      return tooltip.info(
        "Cannot perform this operation on partially merged cells",
        ""
      );
    }
  }

  //多重选区 有条件格式时 提示
  let cdformat = $.extend(true, [], file.luckysheet_conditionformat_save);
  if (range.length > 1 && cdformat.length > 0) {
    let hasCF = false;
    let cf_compute = conditionformat.getComputeMap(file.index);

    for (let s = 0; s < range.length; s++) {
      let r1 = range[s].row[0],
        r2 = range[s].row[1];
      let c1 = range[s].column[0],
        c2 = range[s].column[1];

      for (let r = r1; r <= r2; r++) {
        for (let c = c1; c <= c2; c++) {
          if (conditionformat.checksCF(r, c, cf_compute) != null) {
            hasCF = true;
            break;
          }
        }

        if (hasCF) {
          break;
        }
      }

      if (hasCF) {
        break;
      }
    }

    if (hasCF) {
      return tooltip.info(
        "Cannot perform this operation on multiple selection areas, please select a single area",
        ""
      );
    }
  }

  //多重选区 行不一样且列不一样时 提示
  if (range.length > 1) {
    let isSameRow = true,
      str_r = range[0].row[0],
      end_r = range[0].row[1];
    let isSameCol = true,
      str_c = range[0].column[0],
      end_c = range[0].column[1];

    for (let s = 1; s < range.length; s++) {
      if (range[s].row[0] != str_r || range[s].row[1] != end_r) {
        isSameRow = false;
      }

      if (range[s].column[0] != str_c || range[s].column[1] != end_c) {
        isSameCol = false;
      }
    }

    if ((!isSameRow && !isSameCol) || selectIsOverlap(range)) {
      return tooltip.info(
        "Cannot perform this operation on multiple selection areas, please select a single area",
        ""
      );
    }
  }

  let rowIndexArr = [],
    colIndexArr = [];

  for (let s = 0; s < range.length; s++) {
    let r1 = range[s].row[0],
      r2 = range[s].row[1];
    let c1 = range[s].column[0],
      c2 = range[s].column[1];

    for (let r = r1; r <= r2; r++) {
      if (cfg["rowhidden"] != null && cfg["rowhidden"][r] != null) {
        continue;
      }

      if (!rowIndexArr.includes(r)) {
        rowIndexArr.push(r);
      }

      for (let c = c1; c <= c2; c++) {
        if (cfg["colhidden"] != null && cfg["colhidden"][c] != null) {
          continue;
        }

        if (!colIndexArr.includes(c)) {
          colIndexArr.push(c);
        }
      }
    }
  }

  let borderInfoCompute;
  if (cfg["borderInfo"] && cfg["borderInfo"].length > 0) {
    //边框
    borderInfoCompute = getBorderInfoCompute(file.index);
  }

  let d = file.data;
  if (d == null || d.length == 0) {
    d = sheetmanage.buildGridData(file);
  }

  let cpdata = "";
  let colgroup = "";

  rowIndexArr = rowIndexArr.sort((a, b) => a - b);
  colIndexArr = colIndexArr.sort((a, b) => a - b);

  for (let i = 0; i < rowIndexArr.length; i++) {
    let r = rowIndexArr[i];

    if (cfg["rowhidden"] != null && cfg["rowhidden"][r] != null) {
      continue;
    }

    cpdata += "<tr>";

    for (let j = 0; j < colIndexArr.length; j++) {
      let c = colIndexArr[j];

      if (cfg["colhidden"] != null && cfg["colhidden"][c] != null) {
        continue;
      }

      let column = '<td ${span} style="${style}">';

      if (d[r] != null && d[r][c] != null) {
        let style = "",
          span = "";

        if (r == rowIndexArr[0]) {
          if (
            cfg["columnlen"] == null ||
            cfg["columnlen"][c.toString()] == null
          ) {
            colgroup += '<colgroup width="72px"></colgroup>';
          } else {
            colgroup +=
              '<colgroup width="' +
              cfg["columnlen"][c.toString()] +
              'px"></colgroup>';
          }
        }

        if (c == colIndexArr[0]) {
          if (cfg["rowlen"] == null || cfg["rowlen"][r.toString()] == null) {
            style += "height:19px;";
          } else {
            style += "height:" + cfg["rowlen"][r.toString()] + "px;";
          }
        }

        let reg = /^(w|W)((0?)|(0\.0+))$/;
        let c_value;
        if (
          d[r][c].ct != null &&
          d[r][c].ct.fa != null &&
          d[r][c].ct.fa.match(reg)
        ) {
          c_value = getcellvalue(r, c, d);
        } else {
          c_value = getcellvalue(r, c, d, "m");
        }

        style += menuButton.getStyleByCell(d, r, c);

        if (getObjType(d[r][c]) == "object" && "mc" in d[r][c]) {
          if ("rs" in d[r][c]["mc"]) {
            span =
              'rowspan="' +
              d[r][c]["mc"].rs +
              '" colspan="' +
              d[r][c]["mc"].cs +
              '"';

            //边框
            if (borderInfoCompute && borderInfoCompute[r + "_" + c]) {
              let bl_obj = { color: {}, style: {} },
                br_obj = { color: {}, style: {} },
                bt_obj = { color: {}, style: {} },
                bb_obj = { color: {}, style: {} };

              for (let bd_r = r; bd_r < r + d[r][c]["mc"].rs; bd_r++) {
                for (let bd_c = c; bd_c < c + d[r][c]["mc"].cs; bd_c++) {
                  if (
                    bd_r == r &&
                    borderInfoCompute[bd_r + "_" + bd_c] &&
                    borderInfoCompute[bd_r + "_" + bd_c].t
                  ) {
                    let linetype = borderInfoCompute[bd_r + "_" + bd_c].t.style;
                    let bcolor = borderInfoCompute[bd_r + "_" + bd_c].t.color;

                    if (bt_obj["style"][linetype] == null) {
                      bt_obj["style"][linetype] = 1;
                    } else {
                      bt_obj["style"][linetype] = bt_obj["style"][linetype] + 1;
                    }

                    if (bt_obj["color"][bcolor] == null) {
                      bt_obj["color"][bcolor] = 1;
                    } else {
                      bt_obj["color"][bcolor] = bt_obj["color"][bcolor] + 1;
                    }
                  }

                  if (
                    bd_r == r + d[r][c]["mc"].rs - 1 &&
                    borderInfoCompute[bd_r + "_" + bd_c] &&
                    borderInfoCompute[bd_r + "_" + bd_c].b
                  ) {
                    let linetype = borderInfoCompute[bd_r + "_" + bd_c].b.style;
                    let bcolor = borderInfoCompute[bd_r + "_" + bd_c].b.color;

                    if (bb_obj["style"][linetype] == null) {
                      bb_obj["style"][linetype] = 1;
                    } else {
                      bb_obj["style"][linetype] = bb_obj["style"][linetype] + 1;
                    }

                    if (bb_obj["color"][bcolor] == null) {
                      bb_obj["color"][bcolor] = 1;
                    } else {
                      bb_obj["color"][bcolor] = bb_obj["color"][bcolor] + 1;
                    }
                  }

                  if (
                    bd_c == c &&
                    borderInfoCompute[bd_r + "_" + bd_c] &&
                    borderInfoCompute[bd_r + "_" + bd_c].l
                  ) {
                    let linetype = borderInfoCompute[r + "_" + c].l.style;
                    let bcolor = borderInfoCompute[bd_r + "_" + bd_c].l.color;

                    if (bl_obj["style"][linetype] == null) {
                      bl_obj["style"][linetype] = 1;
                    } else {
                      bl_obj["style"][linetype] = bl_obj["style"][linetype] + 1;
                    }

                    if (bl_obj["color"][bcolor] == null) {
                      bl_obj["color"][bcolor] = 1;
                    } else {
                      bl_obj["color"][bcolor] = bl_obj["color"][bcolor] + 1;
                    }
                  }

                  if (
                    bd_c == c + d[r][c]["mc"].cs - 1 &&
                    borderInfoCompute[bd_r + "_" + bd_c] &&
                    borderInfoCompute[bd_r + "_" + bd_c].r
                  ) {
                    let linetype = borderInfoCompute[bd_r + "_" + bd_c].r.style;
                    let bcolor = borderInfoCompute[bd_r + "_" + bd_c].r.color;

                    if (br_obj["style"][linetype] == null) {
                      br_obj["style"][linetype] = 1;
                    } else {
                      br_obj["style"][linetype] = br_obj["style"][linetype] + 1;
                    }

                    if (br_obj["color"][bcolor] == null) {
                      br_obj["color"][bcolor] = 1;
                    } else {
                      br_obj["color"][bcolor] = br_obj["color"][bcolor] + 1;
                    }
                  }
                }
              }

              let rowlen = d[r][c]["mc"].rs,
                collen = d[r][c]["mc"].cs;

              if (JSON.stringify(bl_obj).length > 23) {
                let bl_color = null,
                  bl_style = null;

                for (let x in bl_obj.color) {
                  if (bl_obj.color[x] >= rowlen / 2) {
                    bl_color = x;
                  }
                }

                for (let x in bl_obj.style) {
                  if (bl_obj.style[x] >= rowlen / 2) {
                    bl_style = x;
                  }
                }

                if (bl_color != null && bl_style != null) {
                  style +=
                    "border-left:" +
                    selection.getHtmlBorderStyle(bl_style, bl_color);
                }
              }

              if (JSON.stringify(br_obj).length > 23) {
                let br_color = null,
                  br_style = null;

                for (let x in br_obj.color) {
                  if (br_obj.color[x] >= rowlen / 2) {
                    br_color = x;
                  }
                }

                for (let x in br_obj.style) {
                  if (br_obj.style[x] >= rowlen / 2) {
                    br_style = x;
                  }
                }

                if (br_color != null && br_style != null) {
                  style +=
                    "border-right:" +
                    selection.getHtmlBorderStyle(br_style, br_color);
                }
              }

              if (JSON.stringify(bt_obj).length > 23) {
                let bt_color = null,
                  bt_style = null;

                for (let x in bt_obj.color) {
                  if (bt_obj.color[x] >= collen / 2) {
                    bt_color = x;
                  }
                }

                for (let x in bt_obj.style) {
                  if (bt_obj.style[x] >= collen / 2) {
                    bt_style = x;
                  }
                }

                if (bt_color != null && bt_style != null) {
                  style +=
                    "border-top:" +
                    selection.getHtmlBorderStyle(bt_style, bt_color);
                }
              }

              if (JSON.stringify(bb_obj).length > 23) {
                let bb_color = null,
                  bb_style = null;

                for (let x in bb_obj.color) {
                  if (bb_obj.color[x] >= collen / 2) {
                    bb_color = x;
                  }
                }

                for (let x in bb_obj.style) {
                  if (bb_obj.style[x] >= collen / 2) {
                    bb_style = x;
                  }
                }

                if (bb_color != null && bb_style != null) {
                  style +=
                    "border-bottom:" +
                    selection.getHtmlBorderStyle(bb_style, bb_color);
                }
              }
            }
          } else {
            continue;
          }
        } else {
          //边框
          if (borderInfoCompute && borderInfoCompute[r + "_" + c]) {
            //左边框
            if (borderInfoCompute[r + "_" + c].l) {
              let linetype = borderInfoCompute[r + "_" + c].l.style;
              let bcolor = borderInfoCompute[r + "_" + c].l.color;
              style +=
                "border-left:" + selection.getHtmlBorderStyle(linetype, bcolor);
            }

            //右边框
            if (borderInfoCompute[r + "_" + c].r) {
              let linetype = borderInfoCompute[r + "_" + c].r.style;
              let bcolor = borderInfoCompute[r + "_" + c].r.color;
              style +=
                "border-right:" +
                selection.getHtmlBorderStyle(linetype, bcolor);
            }

            //下边框
            if (borderInfoCompute[r + "_" + c].b) {
              let linetype = borderInfoCompute[r + "_" + c].b.style;
              let bcolor = borderInfoCompute[r + "_" + c].b.color;
              style +=
                "border-bottom:" +
                selection.getHtmlBorderStyle(linetype, bcolor);
            }

            //上边框
            if (borderInfoCompute[r + "_" + c].t) {
              let linetype = borderInfoCompute[r + "_" + c].t.style;
              let bcolor = borderInfoCompute[r + "_" + c].t.color;
              style +=
                "border-top:" + selection.getHtmlBorderStyle(linetype, bcolor);
            }
          }
        }

        column = replaceHtml(column, { style: style, span: span });

        if (c_value == null) {
          c_value = getcellvalue(r, c, d);
        }

        if (c_value == null) {
          c_value = " ";
        }

        column += c_value;
      } else {
        let style = "";

        //边框
        if (borderInfoCompute && borderInfoCompute[r + "_" + c]) {
          //左边框
          if (borderInfoCompute[r + "_" + c].l) {
            let linetype = borderInfoCompute[r + "_" + c].l.style;
            let bcolor = borderInfoCompute[r + "_" + c].l.color;
            style +=
              "border-left:" + selection.getHtmlBorderStyle(linetype, bcolor);
          }

          //右边框
          if (borderInfoCompute[r + "_" + c].r) {
            let linetype = borderInfoCompute[r + "_" + c].r.style;
            let bcolor = borderInfoCompute[r + "_" + c].r.color;
            style +=
              "border-right:" + selection.getHtmlBorderStyle(linetype, bcolor);
          }

          //下边框
          if (borderInfoCompute[r + "_" + c].b) {
            let linetype = borderInfoCompute[r + "_" + c].b.style;
            let bcolor = borderInfoCompute[r + "_" + c].b.color;
            style +=
              "border-bottom:" + selection.getHtmlBorderStyle(linetype, bcolor);
          }

          //上边框
          if (borderInfoCompute[r + "_" + c].t) {
            let linetype = borderInfoCompute[r + "_" + c].t.style;
            let bcolor = borderInfoCompute[r + "_" + c].t.color;
            style +=
              "border-top:" + selection.getHtmlBorderStyle(linetype, bcolor);
          }
        }

        column += "";

        if (r == rowIndexArr[0]) {
          if (
            cfg["columnlen"] == null ||
            cfg["columnlen"][c.toString()] == null
          ) {
            colgroup += '<colgroup width="72px"></colgroup>';
          } else {
            colgroup +=
              '<colgroup width="' +
              cfg["columnlen"][c.toString()] +
              'px"></colgroup>';
          }
        }

        if (c == colIndexArr[0]) {
          if (cfg["rowlen"] == null || cfg["rowlen"][r.toString()] == null) {
            style += "height:19px;";
          } else {
            style += "height:" + cfg["rowlen"][r.toString()] + "px;";
          }
        }

        column = replaceHtml(column, { style: style, span: "" });
        column += " ";
      }

      column += "</td>";
      cpdata += column;
    }

    cpdata += "</tr>";
  }

  cpdata =
    '<table data-type="luckysheet_copy_action_table">' +
    colgroup +
    cpdata +
    "</table>";

  return cpdata;
}

/**
 * 复制指定工作表指定单元格区域的数据，返回一维、二维或者自定义行列数的二维数组的数据。只有在dimensional设置为custom的时候，才需要设置setting中的row和column
 * @param {String} dimensional 数组维度。可选值为：oneDimensional-一维数组；twoDimensional-二维数组； custom-自定义行列数的二维数组
 * @param {Object} options 可选参数
 * @param {Number} options.row dimensional为custom的时候设置，多维数组的行数
 * @param {Number} options.column dimensional为custom的时候设置，多维数组的列数
 * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]}，只能为单个选区；默认为当前选区
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 */
export function getRangeArray(dimensional, options = {}) {
  let dimensionalValues = ["oneDimensional", "twoDimensional"];

  if (!dimensionalValues.includes(dimensional)) {
    return tooltip.info("The dimensional parameter is invalid.", "");
  }

  let {
    range = Store.luckysheet_select_save[
      Store.luckysheet_select_save.length - 1
    ],
    order = getSheetIndex(Store.currentSheetIndex),
  } = { ...options };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  if (getObjType(range) == "string") {
    if (!formula.iscelldata(range)) {
      return tooltip.info("The range parameter is invalid.", "");
    }

    range = formula.getcellrange(range);
  }

  if (
    getObjType(range) != "object" ||
    range.row == null ||
    range.column == null
  ) {
    return tooltip.info("The range parameter is invalid.", "");
  }

  let r1 = range.row[0],
    r2 = range.row[1];
  let c1 = range.column[0],
    c2 = range.column[1];

  //复制范围内包含部分合并单元格，提示
  let cfg = $.extend(true, {}, file.config);
  if (cfg["merge"] != null) {
    let has_PartMC = hasPartMC(cfg, r1, r2, c1, c2);

    if (has_PartMC) {
      return tooltip.info(
        "Cannot perform this operation on partially merged cells",
        ""
      );
    }
  }

  let data = file.data;
  if (data == null || data.length == 0) {
    data = sheetmanage.buildGridData(file);
  }

  let dataArr = [];

  if (dimensional == "oneDimensional") {
    //一维数组
    for (let r = r1; r <= r2; r++) {
      for (let c = c1; c <= c2; c++) {
        let cell = data[r][c];

        if (cell == null || cell.v == null) {
          dataArr.push(null);
        } else {
          dataArr.push(cell.v);
        }
      }
    }
  } else if (dimensional == "twoDimensional") {
    for (let r = r1; r <= r2; r++) {
      let row = [];

      for (let c = c1; c <= c2; c++) {
        let cell = data[r][c];

        if (cell == null || cell.v == null) {
          row.push(null);
        } else {
          row.push(cell.v);
        }
      }

      dataArr.push(row);
    }
  }

  return dataArr;
}

/**
 * 复制指定工作表指定单元格区域的数据，返回json格式的数据
 * @param {Boolean} isFirstRowTitle 是否首行为标题
 * @param {Object} options 可选参数
 * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]}，只能为单个选区；默认为当前选区
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 */
export function getRangeJson(isFirstRowTitle, options = {}) {
  let curRange = Store.luckysheet_select_save[0];
  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let { range = curRange, order = curSheetOrder } = { ...options };
  let file = Store.luckysheetfile[order];
  let config = file.config;

  if (range && typeof range === "string" && formula.iscelldata(range)) {
    range = formula.getcellrange(range);
  }

  if (!range || range.length > 1) {
    if (isEditMode()) {
      alert(locale_drag.noMulti);
    } else {
      tooltip.info(locale_drag.noMulti, "");
    }
    return;
  }

  //复制范围内包含部分合并单元格，提示
  if (config["merge"] != null) {
    let has_PartMC = false;
    let r1 = range.row[0],
      r2 = range.row[1],
      c1 = range.column[0],
      c2 = range.column[1];
    has_PartMC = hasPartMC(config, r1, r2, c1, c2);

    if (has_PartMC) {
      if (isEditMode()) {
        alert(locale().drag.noPartMerge);
      } else {
        tooltip.info(locale().drag.noPartMerge, "");
      }
      return;
    }
  }
  let getdata = getdatabyselection(range, file.index);
  let arr = [];
  if (getdata.length === 0) {
    return;
  }
  if (isFirstRowTitle) {
    if (getdata.length === 1) {
      let obj = {};
      for (let i = 0; i < getdata[0].length; i++) {
        obj[getcellvalue(0, i, getdata)] = "";
      }
      arr.push(obj);
    } else {
      for (let r = 1; r < getdata.length; r++) {
        let obj = {};
        for (let c = 0; c < getdata[0].length; c++) {
          if (getcellvalue(0, c, getdata) == undefined) {
            obj[""] = getcellvalue(r, c, getdata);
          } else {
            obj[getcellvalue(0, c, getdata)] = getcellvalue(r, c, getdata);
          }
        }
        arr.push(obj);
      }
    }
  } else {
    let st = range["column"][0];
    for (let r = 0; r < getdata.length; r++) {
      let obj = {};
      for (let c = 0; c < getdata[0].length; c++) {
        obj[chatatABC(c + st)] = getcellvalue(r, c, getdata);
      }
      arr.push(obj);
    }
  }
  // selection.copybyformat(new Event('click'), JSON.stringify(arr));
  return arr;
}

/**
 *
 * @param {String} type 对角线还是对角线偏移 "normal"-对角线  "anti"-反对角线
"offset"-对角线偏移
 * @param {Object} options 可选参数
 * @param {Number} options.column type为offset的时候设置，对角偏移的列数
 * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]}，只能为单个选区；默认为当前选区
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 */
export function getRangeDiagonal(type, options = {}) {
  let typeValues = ["normal", "anti", "offset"];
  if (typeValues.indexOf(type) < 0) {
    return tooltip.info(
      "The type parameter must be included in ['normal', 'anti', 'offset']",
      ""
    );
  }

  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let curRange = JSON.parse(JSON.stringify(Store.luckysheet_select_save));
  let { column = 1, range = curRange, order = curSheetOrder } = { ...options };

  let file = Store.luckysheetfile[order];
  let config = file.config;

  if (range && typeof range === "string" && formula.iscelldata(range)) {
    range = formula.getcellrange(range);
  }

  if (!range || range.length > 1) {
    if (isEditMode()) {
      alert(locale().drag.noMulti);
    } else {
      tooltip.info(locale().drag.noMulti, "");
    }
    return;
  }

  //复制范围内包含部分合并单元格，提示
  if (config["merge"] != null) {
    let has_PartMC = false;
    let r1 = range[0].row[0],
      r2 = range[0].row[1],
      c1 = range[0].column[0],
      c2 = range[0].column[1];
    has_PartMC = hasPartMC(config, r1, r2, c1, c2);

    if (has_PartMC) {
      if (isEditMode()) {
        alert(locale().drag.noPartMerge);
      } else {
        tooltip.info(locale().drag.noPartMerge, "");
      }
      return;
    }
  }
  let getdata = getdatabyselection(range, order);
  let arr = [];
  if (getdata.length === 0) {
    return;
  }

  let clen = getdata[0].length;
  switch (type) {
    case "normal":
      for (let r = 0; r < getdata.length; r++) {
        if (r >= clen) {
          break;
        }
        arr.push(getdata[r][r]);
      }
      break;
    case "anti":
      for (let r = 0; r < getdata.length; r++) {
        if (r >= clen) {
          break;
        }
        arr.push(getdata[r][clen - r - 1]);
      }
      break;
    case "offset":
      if (column.toString() == "NaN") {
        if (isEditMode()) {
          alert(locale().drag.inputCorrect);
        } else {
          tooltip.info(locale().drag.inputCorrect, "");
        }
        return;
      }

      if (column < 0) {
        if (isEditMode()) {
          alert(locale().drag.offsetColumnLessZero);
        } else {
          tooltip.info(locale().drag.offsetColumnLessZero, "");
        }
        return;
      }

      for (let r = 0; r < getdata.length; r++) {
        if (r + column >= clen) {
          break;
        }
        arr.push(getdata[r][r + column]);
      }
      break;
  }
  selection.copybyformat(new Event(), JSON.stringify(arr));
}

/**
 * 复制指定工作表指定单元格区域的数据，返回布尔值的数据
 * @param {Object} options 可选参数
 * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]}，只能为单个选区；默认为当前选区
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 */
export function getRangeBoolean(options = {}) {
  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let curRange = JSON.parse(JSON.stringify(Store.luckysheet_select_save));
  let { range = curRange, order = curSheetOrder } = { ...options };

  let file = Store.luckysheetfile[order];
  let config = file.config;

  if (range && typeof range === "string" && formula.iscelldata(range)) {
    range = formula.getcellrange(range);
  }

  if (!range || range.length > 1) {
    if (isEditMode()) {
      alert(locale().drag.noMulti);
    } else {
      tooltip.info(locale().drag.noMulti, "");
    }
    return;
  }

  //复制范围内包含部分合并单元格，提示
  if (config["merge"] != null) {
    let has_PartMC = false;
    let r1 = range[0].row[0],
      r2 = range[0].row[1],
      c1 = range[0].column[0],
      c2 = range[0].column[1];
    has_PartMC = hasPartMC(config, r1, r2, c1, c2);

    if (has_PartMC) {
      if (isEditMode()) {
        alert(locale().drag.noPartMerge);
      } else {
        tooltip.info(locale().drag.noPartMerge, "");
      }
      return;
    }
  }
  let getdata = getdatabyselection(range, order);
  let arr = [];
  if (getdata.length === 0) {
    return;
  }
  for (let r = 0; r < getdata.length; r++) {
    let a = [];
    for (let c = 0; c < getdata[0].length; c++) {
      let bool = false;

      let v;
      if (getObjType(getdata[r][c]) == "object") {
        v = getdata[r][c].v;
      } else {
        v = getdata[r][c];
      }

      if (v == null || v == "") {
        bool = false;
      } else {
        v = parseInt(v);
        if (v == null || v > 0) {
          bool = true;
        } else {
          bool = false;
        }
      }
      a.push(bool);
    }
    arr.push(a);
  }

  selection.copybyformat(event, JSON.stringify(arr));
}

/**
 * 指定工作表选中一个或多个选区为选中状态并选择是否高亮，支持多种格式设置。
 * @param {Array | Object | String} range 选区范围
 * @param {Object} options 可选参数
 * @param {Boolean} options.show 是否显示高亮选中效果；默认值为 `true`
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 * @param {Function} options.success 操作结束的回调函数
 */
export function setRangeShow(range, options = {}) {
  if (getObjType(range) == "string") {
    if (!formula.iscelldata(range)) {
      return tooltip.info("The range parameter is invalid.", "");
    }

    let cellrange = formula.getcellrange(range);
    range = [
      {
        row: cellrange.row,
        column: cellrange.column,
      },
    ];
  } else if (getObjType(range) == "object") {
    if (range.row == null || range.column == null) {
      return tooltip.info("The range parameter is invalid.", "");
    }

    range = [
      {
        row: range.row,
        column: range.column,
      },
    ];
  }

  if (getObjType(range) == "array") {
    for (let i = 0; i < range.length; i++) {
      if (getObjType(range[i]) === "string") {
        if (!formula.iscelldata(range[i])) {
          return tooltip.info("The range parameter is invalid.", "");
        }
        let cellrange = formula.getcellrange(range[i]);
        range[i] = {
          row: cellrange.row,
          column: cellrange.column,
        };
      } else if (getObjType(range) == "object") {
        if (range.row == null || range.column == null) {
          return tooltip.info("The range parameter is invalid.", "");
        }
        range = {
          row: range.row,
          column: range.column,
        };
      }
    }
  }

  if (getObjType(range) != "array") {
    return tooltip.info("The range parameter is invalid.", "");
  }

  let {
    show = true,
    order = getSheetIndex(Store.currentSheetIndex),
    success,
  } = { ...options };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  for (let i = 0; i < range.length; i++) {
    let changeparam = menuButton.mergeMoveMain(
      range[i].column,
      range[i].row,
      range[i]
    );
    if (changeparam) {
      range[i] = {
        row: changeparam[1],
        column: changeparam[0],
      };
    }
  }

  file.luckysheet_select_save = range;

  if (file.index == Store.currentSheetIndex) {
    Store.luckysheet_select_save = range;
    selectHightlightShow();

    if (!show) {
      $("#luckysheet-cell-selected-boxs").hide();
      $("#luckysheet-cell-selected-focus").hide();
      $("#luckysheet-row-count-show").hide();
      $("#luckysheet-column-count-show").hide();
      $("#luckysheet-rows-h-selected").empty();
      $("#luckysheet-cols-h-selected").empty();
    }
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 将一个单元格数组数据赋值到指定的区域，数据格式同getRangeValue方法取到的数据。
 * @param {Array[Array]} data 要赋值的单元格二维数组数据，每个单元格的值，可以为字符串或数字，或为符合Luckysheet格式的对象
 * @param {Object} options 可选参数
 * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]}，只能为单个选区；默认为当前选区
 * @param {Boolean} options.isRefresh 是否刷新界面；默认为true
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function setRangeValue(data, options = {}) {
  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let curRange =
    Store.luckysheet_select_save[Store.luckysheet_select_save.length - 1];
  let { range = curRange, isRefresh = true, order = curSheetOrder, success } = {
    ...options,
  };

  if (data == null) {
    return tooltip.info(
      "The data which will be set to range cannot be null.",
      ""
    );
  }

  if (range instanceof Array) {
    return tooltip.info("setRangeValue only supports a single selection.", "");
  }

  if (typeof range === "string" && formula.iscelldata(range)) {
    range = formula.getcellrange(range);
  }

  let rowCount = range.row[1] - range.row[0] + 1,
    columnCount = range.column[1] - range.column[0] + 1;

  if (data.length !== rowCount || data[0].length !== columnCount) {
    return tooltip.info("The data to be set does not match the selection.", "");
  }

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }
  let sheetData = $.extend(true, [], file.data);

  for (let i = 0; i < rowCount; i++) {
    for (let j = 0; j < columnCount; j++) {
      let row = range.row[0] + i,
        column = range.column[0] + j;
      setCellValue(row, column, data[i][j], { order: order, isRefresh: false });
    }
  }

  let fileData = $.extend(true, [], file.data);
  file.data.length = 0;
  file.data.push(...sheetData);

  if (file.index == Store.currentSheetIndex) {
    jfrefreshgrid(
      fileData,
      [
        {
          row: range.row,
          column: range.column,
        },
      ],
      undefined,
      true,
      false
    );
  }

  if (isRefresh) {
    luckysheetrefreshgrid();
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 设置指定范围的单元格格式，一般用作处理格式，赋值操作推荐使用setRangeValue方法
 * @param {String} attr 要赋值的单元格二维数组数据，每个单元格的值，可以为字符串或数字，或为符合Luckysheet格式的对象
 * @param {Number | String | Object} value 具体的设置值
 * @param {Object} options 可选参数
 * @param {Object | String} options.range 设置参数的目标选区范围，支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]}，只能为单个选区；默认为当前选区
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 */
export function setSingleRangeFormat(attr, value, options = {}) {
  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let curRange =
    Store.luckysheet_select_save[Store.luckysheet_select_save.length - 1];
  let { range = curRange, order = curSheetOrder } = { ...options };

  if (!attr) {
    tooltip.info("Arguments attr cannot be null or undefined.", "");
    return "error";
  }

  if (range instanceof Array) {
    tooltip.info("setRangeValue only supports a single selection.", "");
    return "error";
  }

  if (getObjType(range) == "string") {
    if (!formula.iscelldata(range)) {
      tooltip.info("The range parameter is invalid.", "");
      return "error";
    }

    range = formula.getcellrange(range);
  }

  if (
    getObjType(range) != "object" ||
    range.row == null ||
    range.column == null
  ) {
    tooltip.info("The range parameter is invalid.", "");
    return "error";
  }

  for (let r = range.row[0]; r <= range.row[1]; r++) {
    for (let c = range.column[0]; c <= range.column[1]; c++) {
      console.log("r", r);
      console.log("c", c);
      setCellValue(
        r,
        c,
        { [attr]: value },
        {
          order: order,
          isRefresh: false,
        }
      );
    }
  }
}

/**
 * 设置指定范围的单元格格式，一般用作处理格式。支持多选区设置
 * @param {String} attr 要赋值的单元格二维数组数据，每个单元格的值，可以为字符串或数字，或为符合Luckysheet格式的对象
 * @param {Number | String | Object} value 具体的设置值
 * @param {Object} options 可选参数
 * @param {Array | Object | String} options.range 设置参数的目标选区范围，支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]}，只能为单个选区；默认为当前选区
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function setRangeFormat(attr, value, options = {}) {
  let curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let curRange = JSON.parse(JSON.stringify(Store.luckysheet_select_save));
  let { range = curRange, order = curSheetOrder, success } = { ...options };

  if (getObjType(range) == "string") {
    if (!formula.iscelldata(range)) {
      return tooltip.info("The range parameter is invalid.", "");
    }

    let cellrange = formula.getcellrange(range);
    range = [
      {
        row: cellrange.row,
        column: cellrange.column,
      },
    ];
  } else if (getObjType(range) == "object") {
    if (range.row == null || range.column == null) {
      return tooltip.info("The range parameter is invalid.", "");
    }

    range = [
      {
        row: range.row,
        column: range.column,
      },
    ];
  }

  if (getObjType(range) != "array") {
    return tooltip.info("The range parameter is invalid.", "");
  }

  let file = Store.luckysheetfile[order];

  let result = [];

  for (let i = 0; i < range.length; i++) {
    result.push(
      setSingleRangeFormat(attr, value, { range: range[i], order: order })
    );
  }

  let fileData = $.extend(true, [], file.data);
  if (result.some((i) => i === "error")) {
    file.data.length = 0;
    file.data.push(...fileData);
    return false;
  }

  file.data.length = 0;
  file.data.push(...fileData);

  if (file.index == Store.currentSheetIndex) {
    jfrefreshgrid(fileData, undefined, undefined, true, false);
  }

  luckysheetrefreshgrid();

  if (success && typeof success === "function") {
  }
}

/**
 * 为指定索引的工作表，选定的范围开启或关闭筛选功能
 * @param {String} type 打开还是关闭筛选功能  open-打开筛选功能，返回当前筛选的范围对象；close-关闭筛选功能，返回关闭前筛选的范围对象
 * @param {Object} options 可选参数
 * @param {Object | String} options.range 选区范围
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 * @param {Object} options.success 操作结束的回调函数
 */
export function setRangeFilter(type, options = {}) {
  let typeValues = ["open", "close"];

  if (!typeValues.includes(type)) {
    return tooltip.info("The type parameter is invalid.", "");
  }

  let {
    range = Store.luckysheet_select_save[
      Store.luckysheet_select_save.length - 1
    ],
    order = getSheetIndex(Store.currentSheetIndex),
    success,
  } = { ...options };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  if (getObjType(range) == "string") {
    if (!formula.iscelldata(range)) {
      return tooltip.info("The range parameter is invalid.", "");
    }

    range = formula.getcellrange(range);
  }

  if (
    getObjType(range) != "object" ||
    range.row == null ||
    range.column == null
  ) {
    return tooltip.info("The range parameter is invalid.", "");
  }

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 1);

  if (type == "open") {
    file.filter_select = range;

    if (file.index == Store.currentSheetIndex) {
      createFilterOptions(range, file.filter);
    }

    return {
      row: range.row,
      column: range.column,
    };
  } else if (type == "close") {
    let luckysheet_filter_save = $.extend(true, {}, file.filter_select);

    file.filter_select = null;

    $("#luckysheet-filter-selected-sheet" + file.index).remove();
    $("#luckysheet-filter-options-sheet" + file.index).remove();

    return {
      row: luckysheet_filter_save.row,
      column: luckysheet_filter_save.column,
    };
  }
}

/**
 * 为指定索引的工作表，选定的范围设定合并单元格
 * @param {String} type 合并类型 all-全部合并  horizontal-水平合并  vertical-垂直合并
 * @param {Object} options 可选参数
 * @param {Object | String} options.range 选区范围
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Object} options.success 操作结束的回调函数
 */
export function setRangeMerge(type, options = {}) {
  let typeValues = ["all", "horizontal", "vertical"];
  if (typeValues.indexOf(type) < 0) {
    return tooltip.info(
      "The type parameter must be included in ['all', 'horizontal', 'vertical']",
      ""
    );
  }

  let curSheetOrder = getSheetIndex(Store.currentSheetIndex),
    curRange = JSON.parse(JSON.stringify(Store.luckysheet_select_save));
  let { range = curRange, order = curSheetOrder, success } = { ...options };

  let file = Store.luckysheetfile[order],
    cfg = $.extend(true, {}, file.config),
    data = $.extend(true, [], file.data);

  if (data.length == 0) {
    data = $.extend(true, [], sheetmanage.buildGridData(file));
  }

  if (getObjType(range) == "string") {
    if (!formula.iscelldata(range)) {
      return tooltip.info("Incorrect selection format", "");
    }

    let cellrange = formula.getcellrange(range);
    range = [
      {
        row: cellrange.row,
        column: cellrange.column,
      },
    ];
  } else if (getObjType(range) == "object") {
    if (!range.hasOwnProperty("row") || !range.hasOwnProperty("column")) {
      return tooltip.info("Incorrect selection format", "");
    }

    range = [
      {
        row: range.row,
        column: range.column,
      },
    ];
  }

  //不能合并重叠区域
  if (selectIsOverlap(range)) {
    return tooltip.info("Cannot merge overlapping range", "");
  }

  //选区是否含有 部分合并单元格
  if (cfg["merge"] != null) {
    let has_PartMC = false;

    for (let s = 0; s < range.length; s++) {
      let r1 = range[s].row[0],
        r2 = range[s].row[1];
      let c1 = range[s].column[0],
        c2 = range[s].column[1];

      has_PartMC = hasPartMC(cfg, r1, r2, c1, c2);

      if (has_PartMC) {
        break;
      }
    }

    if (has_PartMC) {
      return tooltip.info(
        "Cannot perform this operation on partially merged cells",
        ""
      );
    }
  } else {
    cfg.merge = {};
  }

  //选区是否含有 合并的单元格
  let isHasMc = false;

  for (let i = 0; i < range.length; i++) {
    let r1 = range[i].row[0],
      r2 = range[i].row[1];
    let c1 = range[i].column[0],
      c2 = range[i].column[1];

    for (let r = r1; r <= r2; r++) {
      for (let c = c1; c <= c2; c++) {
        let cell = data[r][c];

        if (getObjType(cell) == "object" && "mc" in cell) {
          isHasMc = true;
          break;
        }
      }

      if (isHasMc) {
        break;
      }
    }
  }

  if (isHasMc) {
    //选区有合并单元格（选区都执行 取消合并）
    cancelRangeMerge({
      range: range,
      order: order,
    });
  } else {
    for (let i = 0; i < range.length; i++) {
      let r1 = range[i].row[0],
        r2 = range[i].row[1];
      let c1 = range[i].column[0],
        c2 = range[i].column[1];

      if (r1 == r2 && c1 == c2) {
        continue;
      }

      if (type == "all") {
        let fv = {},
          isfirst = false;

        for (let r = r1; r <= r2; r++) {
          for (let c = c1; c <= c2; c++) {
            let cell = data[r][c];

            if (
              cell != null &&
              (!isRealNull(cell.v) || cell.f != null) &&
              !isfirst
            ) {
              fv = $.extend(true, {}, cell);
              isfirst = true;
            }

            data[r][c] = { mc: { r: r1, c: c1 } };
          }
        }

        data[r1][c1] = fv;
        data[r1][c1].mc = { r: r1, c: c1, rs: r2 - r1 + 1, cs: c2 - c1 + 1 };

        cfg["merge"][r1 + "_" + c1] = {
          r: r1,
          c: c1,
          rs: r2 - r1 + 1,
          cs: c2 - c1 + 1,
        };
      } else if (type == "vertical") {
        for (let c = c1; c <= c2; c++) {
          let fv = {},
            isfirst = false;

          for (let r = r1; r <= r2; r++) {
            let cell = data[r][c];

            if (
              cell != null &&
              (!isRealNull(cell.v) || cell.f != null) &&
              !isfirst
            ) {
              fv = $.extend(true, {}, cell);
              isfirst = true;
            }

            data[r][c] = { mc: { r: r1, c: c } };
          }

          data[r1][c] = fv;
          data[r1][c].mc = { r: r1, c: c, rs: r2 - r1 + 1, cs: 1 };

          cfg["merge"][r1 + "_" + c] = { r: r1, c: c, rs: r2 - r1 + 1, cs: 1 };
        }
      } else if (type == "horizontal") {
        for (let r = r1; r <= r2; r++) {
          let fv = {},
            isfirst = false;

          for (let c = c1; c <= c2; c++) {
            let cell = data[r][c];

            if (
              cell != null &&
              (!isRealNull(cell.v) || cell.f != null) &&
              !isfirst
            ) {
              fv = $.extend(true, {}, cell);
              isfirst = true;
            }

            data[r][c] = { mc: { r: r, c: c1 } };
          }

          data[r][c1] = fv;
          data[r][c1].mc = { r: r, c: c1, rs: 1, cs: c2 - c1 + 1 };

          cfg["merge"][r + "_" + c1] = { r: r, c: c1, rs: 1, cs: c2 - c1 + 1 };
        }
      }
    }

    if (order == curSheetOrder) {
      if (Store.clearjfundo) {
        Store.jfundo.length = 0;
        Store.jfredo.push({
          type: "mergeChange",
          sheetIndex: file.index,
          data: $.extend(true, [], file.data),
          curData: data,
          range: range,
          config: $.extend(true, {}, file.config),
          curConfig: cfg,
        });
      }

      Store.clearjfundo = false;
      jfrefreshgrid(data, range, { cfg: cfg });
      Store.clearjfundo = true;
    } else {
      file.data = data;
      file.config = cfg;
    }
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 为指定索引的工作表，选定的范围取消合并单元格
 * @param {Object} options 可选参数
 * @param {Array | Object | String} options.range 选区范围
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Object} options.success 操作结束的回调函数
 */
export function cancelRangeMerge(options = {}) {
  let curRange = Store.luckysheet_select_save,
    curSheetOrder = getSheetIndex(Store.currentSheetIndex);
  let { range = curRange, order = curSheetOrder, success } = { ...options };

  let file = Store.luckysheetfile[order],
    cfg = $.extend(true, {}, file.config),
    data = $.extend(true, [], file.data);

  if (data.length == 0) {
    data = $.extend(true, [], sheetmanage.buildGridData(file));
  }

  if (getObjType(range) == "string") {
    if (!formula.iscelldata(range)) {
      return tooltip.info("Incorrect selection format", "");
    }

    let cellrange = formula.getcellrange(range);
    range = [
      {
        row: cellrange.row,
        column: cellrange.column,
      },
    ];
  } else if (getObjType(range) == "object") {
    if (!range.hasOwnProperty("row") || !range.hasOwnProperty("column")) {
      return tooltip.info("Incorrect selection format", "");
    }

    range = [
      {
        row: range.row,
        column: range.column,
      },
    ];
  }

  //不能合并重叠区域
  if (selectIsOverlap(range)) {
    return tooltip.info("Cannot merge overlapping range", "");
  }

  //选区是否含有 部分合并单元格
  if (cfg["merge"] != null) {
    let has_PartMC = false;

    for (let s = 0; s < range.length; s++) {
      let r1 = range[s].row[0],
        r2 = range[s].row[1];
      let c1 = range[s].column[0],
        c2 = range[s].column[1];

      has_PartMC = hasPartMC(cfg, r1, r2, c1, c2);

      if (has_PartMC) {
        break;
      }
    }

    if (has_PartMC) {
      return tooltip.info(
        "Cannot perform this operation on partially merged cells",
        ""
      );
    }
  }

  for (let i = 0; i < range.length; i++) {
    let r1 = range[i].row[0],
      r2 = range[i].row[1];
    let c1 = range[i].column[0],
      c2 = range[i].column[1];

    if (r1 == r2 && c1 == c2) {
      continue;
    }

    let fv = {};

    for (let r = r1; r <= r2; r++) {
      for (let c = c1; c <= c2; c++) {
        let cell = data[r][c];

        if (cell != null && cell.mc != null) {
          let mc_r = cell.mc.r,
            mc_c = cell.mc.c;

          if ("rs" in cell.mc) {
            delete cell.mc;
            delete cfg["merge"][mc_r + "_" + mc_c];

            fv[mc_r + "_" + mc_c] = $.extend(true, {}, cell);
          } else {
            // let cell_clone = fv[mc_r + "_" + mc_c];
            let cell_clone = JSON.parse(JSON.stringify(fv[mc_r + "_" + mc_c]));

            delete cell_clone.v;
            delete cell_clone.m;
            delete cell_clone.ct;
            delete cell_clone.f;
            delete cell_clone.spl;

            data[r][c] = cell_clone;
          }
        }
      }
    }
  }

  if (order == curSheetOrder) {
    if (Store.clearjfundo) {
      Store.jfundo.length = 0;
      Store.jfredo.push({
        type: "mergeChange",
        sheetIndex: file.index,
        data: $.extend(true, [], file.data),
        curData: data,
        range: range,
        config: $.extend(true, {}, file.config),
        curConfig: cfg,
      });
    }

    Store.clearjfundo = false;
    jfrefreshgrid(data, range, { cfg: cfg });
    Store.clearjfundo = true;
  } else {
    file.data = data;
    file.config = cfg;
  }
}

/**
 * 为指定索引的工作表，选定的范围开启排序功能，返回选定范围排序后的数据。
 * @param {String} type 排序类型 asc-升序 desc-降序
 * @param {Object} options 可选参数
 * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]}，只能为单个选区；默认为当前选区
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function setRangeSort(type, options = {}) {
  let typeValues = ["asc", "desc"];
  if (typeValues.indexOf(type) < 0) {
    return tooltip.info(
      "The type parameter must be included in ['asc', 'desc'",
      ""
    );
  }

  let curSheetOrder = getSheetIndex(Store.currentSheetIndex),
    curRange = Store.luckysheet_select_save[0];
  let { range = curRange, order = curSheetOrder, success } = { ...options };

  let file = Store.luckysheetfile[order],
    cfg = $.extend(true, {}, file.config),
    fileData = $.extend(true, [], file.data);

  if (fileData.length == 0) {
    fileData = $.extend(true, [], sheetmanage.buildGridData(file));
  }

  if (range instanceof Array && range.length > 1) {
    tooltip.info(locale().sort.noRangeError, "");
    return;
  }

  if (range && typeof range === "string" && formula.iscelldata(range)) {
    range = formula.getcellrange(range);
  }

  let r1 = range.row[0],
    r2 = range.row[1],
    c1 = range.column[0],
    c2 = range.column[1];

  let hasMc = false; //Whether the sort selection has merged cells
  let data = [];
  for (let r = r1; r <= r2; r++) {
    let data_row = [];
    for (let c = c1; c <= c2; c++) {
      if (fileData[r][c] != null && fileData[r][c].mc != null) {
        hasMc = true;
        break;
      }
      data_row.push(fileData[r][c]);
    }
    data.push(data_row);
  }

  if (hasMc) {
    tooltip.info(locale().sort.mergeError, "");
    return;
  }

  data = orderbydata([].concat(data), 0, type === "asc");

  for (let r = r1; r <= r2; r++) {
    for (let c = c1; c <= c2; c++) {
      fileData[r][c] = data[r - r1][c - c1];
    }
  }

  let allParam = {};
  if (cfg["rowlen"] != null) {
    cfg = rowlenByRange(fileData, r1, r2, cfg);

    allParam = {
      cfg: cfg,
      RowlChange: true,
    };
  }

  if (file.index == Store.currentSheetIndex) {
    jfrefreshgrid(fileData, [{ row: [r1, r2], column: [c1, c2] }], allParam);
  } else {
    file.data = fileData;
    file.config = cfg;
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 为指定索引的工作表，选定的范围开启多列自定义排序功能，返回选定范围排序后的数据。
 * @param {Boolean} hasTitle 数据是否具有标题行
 * @param {Array} sort 列设置，设置需要排序的列索引和排序方式，格式如：[{ i:0,sort:'asc' },{ i:1,sort:'des' }]
 * @param {Object} options 可选参数
 * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]}，只能为单个选区；默认为当前选区
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function setRangeSortMulti(hasTitle, sort, options = {}) {
  if (!sort || !(sort instanceof Array)) {
    return tooltip.info("The sort parameter is invalid.", "");
  }

  let curSheetOrder = getSheetIndex(Store.currentSheetIndex),
    curRange = Store.luckysheet_select_save[0];
  let { range = curRange, order = curSheetOrder, success } = { ...options };

  let file = Store.luckysheetfile[order],
    cfg = $.extend(true, {}, file.config),
    fileData = $.extend(true, [], file.data);

  if (fileData.length == 0) {
    fileData = $.extend(true, [], sheetmanage.buildGridData(file));
  }

  if (range instanceof Array && range.length > 1) {
    tooltip.info(locale().sort.noRangeError, "");
    return;
  }

  if (range && typeof range === "string" && formula.iscelldata(range)) {
    range = formula.getcellrange(range);
  }

  let r1 = range.row[0],
    r2 = range.row[1],
    c1 = range.column[0],
    c2 = range.column[1];

  let str;
  if (hasTitle) {
    str = r1 + 1;
  } else {
    str = r1;
  }

  let hasMc = false; //Whether the sort selection has merged cells
  let data = [];
  for (let r = str; r <= r2; r++) {
    let data_row = [];
    for (let c = c1; c <= c2; c++) {
      if (fileData[r][c] != null && fileData[r][c].mc != null) {
        hasMc = true;
        break;
      }
      data_row.push(fileData[r][c]);
    }
    data.push(data_row);
  }

  if (hasMc) {
    tooltip.info(locale().sort.mergeError, "");
    return;
  }

  sort.forEach((sortItem) => {
    let i = sortItem.i;
    i -= c1;
    data = orderbydata([].concat(data), i, sortItem.sort === "asc");
  });

  for (let r = str; r <= r2; r++) {
    for (let c = c1; c <= c2; c++) {
      fileData[r][c] = data[r - str][c - c1];
    }
  }

  let allParam = {};
  if (cfg["rowlen"] != null) {
    cfg = rowlenByRange(fileData, str, r2, cfg);

    allParam = {
      cfg: cfg,
      RowlChange: true,
    };
  }

  if (file.index === Store.currentSheetIndex) {
    jfrefreshgrid(fileData, [{ row: [str, r2], column: [c1, c2] }], allParam);
  } else {
    file.data = fileData;
    file.config = cfg;
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 *  为指定索引的工作表，选定的范围开启条件格式，根据设置的条件格式规则突出显示部分单元格，返回开启条件格式后的数据。
 * @param {String} conditionName 条件格式规则类型
 * @param {Object} conditionValue 可以设置条件单元格或者条件值
 * @param {Object} options 可选参数
 * @param {Object} options.format 颜色设置
 * @param {Array | Object | String} options.cellrange 选区范围
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function setRangeConditionalFormatDefault(
  conditionName,
  conditionValue,
  options = {}
) {
  let conditionNameValues = [
    "greaterThan",
    "lessThan",
    "betweenness",
    "equal",
    "textContains",
    "occurrenceDate",
    "duplicateValue",
    "top10",
    "top10%",
    "last10",
    "last10%",
    "AboveAverage",
    "SubAverage",
  ];

  if (!conditionName || !conditionNameValues.includes(conditionName)) {
    return tooltip.info("The conditionName parameter is invalid.", "");
  }

  if (getObjType(conditionValue) != "array" || conditionValue.length == 0) {
    return tooltip.info("The conditionValue parameter is invalid.", "");
  }

  let {
    format = {
      textColor: "#000000",
      cellColor: "#ff0000",
    },
    cellrange = Store.luckysheet_select_save,
    order = getSheetIndex(Store.currentSheetIndex),
    success,
  } = { ...options };

  cellrange = JSON.parse(JSON.stringify(cellrange));

  let file = Store.luckysheetfile[order];
  let data = file.data;

  if (data == null || data.length == 0) {
    data = sheetmanage.buildGridData(file);
  }

  if (file == null) {
    return tooltip.info("Incorrect worksheet index", "");
  }

  const conditionformat_Text = locale().conditionformat;

  let conditionRange = [],
    conditionValue2 = [];

  if (conditionName == "betweenness") {
    let v1 = conditionValue[0];
    let v2 = conditionValue[1];

    //条件值是否是选区
    let rangeArr1 = conditionformat.getRangeByTxt(v1);
    if (rangeArr1.length > 1) {
      conditionformat.infoDialog(conditionformat_Text.onlySingleCell, "");
      return;
    } else if (rangeArr1.length == 1) {
      let r1 = rangeArr1[0].row[0],
        r2 = rangeArr1[0].row[1];
      let c1 = rangeArr1[0].column[0],
        c2 = rangeArr1[0].column[1];

      if (r1 == r2 && c1 == c2) {
        v1 = getcellvalue(r1, c1, data);

        conditionRange.push({
          row: rangeArr1[0].row,
          column: rangeArr1[0].column,
        });
        conditionValue2.push(v1);
      } else {
        conditionformat.infoDialog(conditionformat_Text.onlySingleCell, "");
        return;
      }
    } else if (rangeArr1.length == 0) {
      if (isNaN(v1) || v1 == "") {
        conditionformat.infoDialog(
          conditionformat_Text.conditionValueCanOnly,
          ""
        );
        return;
      } else {
        conditionValue2.push(v1);
      }
    }

    let rangeArr2 = conditionformat.getRangeByTxt(v2);
    if (rangeArr2.length > 1) {
      conditionformat.infoDialog(conditionformat_Text.onlySingleCell, "");
      return;
    } else if (rangeArr2.length == 1) {
      let r1 = rangeArr2[0].row[0],
        r2 = rangeArr2[0].row[1];
      let c1 = rangeArr2[0].column[0],
        c2 = rangeArr2[0].column[1];

      if (r1 == r2 && c1 == c2) {
        v2 = getcellvalue(r1, c1, data);

        conditionRange.push({
          row: rangeArr2[0].row,
          column: rangeArr2[0].column,
        });
        conditionValue2.push(v2);
      } else {
        conditionformat.infoDialog(conditionformat_Text.onlySingleCell, "");
        return;
      }
    } else if (rangeArr2.length == 0) {
      if (isNaN(v2) || v2 == "") {
        conditionformat.infoDialog(
          conditionformat_Text.conditionValueCanOnly,
          ""
        );
        return;
      } else {
        conditionValue2.push(v2);
      }
    }
  } else if (
    conditionName == "greaterThan" ||
    conditionName == "lessThan" ||
    conditionName == "equal"
  ) {
    let v = conditionValue[0];

    //条件值是否是选区
    let rangeArr = conditionformat.getRangeByTxt(v);
    if (rangeArr.length > 1) {
      conditionformat.infoDialog(conditionformat_Text.onlySingleCell, "");
      return;
    } else if (rangeArr.length == 1) {
      let r1 = rangeArr[0].row[0],
        r2 = rangeArr[0].row[1];
      let c1 = rangeArr[0].column[0],
        c2 = rangeArr[0].column[1];

      if (r1 == r2 && c1 == c2) {
        v = getcellvalue(r1, c1, data);

        conditionRange.push({
          row: rangeArr[0].row,
          column: rangeArr[0].column,
        });
        conditionValue2.push(v);
      } else {
        conditionformat.infoDialog(conditionformat_Text.onlySingleCell, "");
        return;
      }
    } else if (rangeArr.length == 0) {
      if (isNaN(v) || v == "") {
        conditionformat.infoDialog(
          conditionformat_Text.conditionValueCanOnly,
          ""
        );
        return;
      } else {
        conditionValue2.push(v);
      }
    }
  } else if (conditionName == "textContains") {
    let v = conditionValue[0];

    //条件值是否是选区
    let rangeArr = conditionformat.getRangeByTxt(v);
    if (rangeArr.length > 1) {
      conditionformat.infoDialog(conditionformat_Text.onlySingleCell, "");
      return;
    } else if (rangeArr.length == 1) {
      let r1 = rangeArr[0].row[0],
        r2 = rangeArr[0].row[1];
      let c1 = rangeArr[0].column[0],
        c2 = rangeArr[0].column[1];

      if (r1 == r2 && c1 == c2) {
        v = getcellvalue(r1, c1, data);

        conditionRange.push({
          row: rangeArr[0].row,
          column: rangeArr[0].column,
        });
        conditionValue2.push(v);
      } else {
        conditionformat.infoDialog(conditionformat_Text.onlySingleCell, "");
        return;
      }
    } else if (rangeArr.length == 0) {
      if (v == "") {
        conditionformat.infoDialog(
          conditionformat_Text.conditionValueCanOnly,
          ""
        );
        return;
      } else {
        conditionValue2.push(v);
      }
    }
  } else if (conditionName == "occurrenceDate") {
    let v1 = conditionValue[0];
    let v2 = conditionValue[1];

    if (!isdatetime(v1) || !isdatetime(v2)) {
      return tooltip.info("The conditionValue parameter is invalid.", "");
    }

    let v;
    if (diff(v1, v2) > 0) {
      v = dayjs(v2).format("YYYY/MM/DD") + "-" + dayjs(v1).format("YYYY/MM/DD");
    } else {
      v = dayjs(v1).format("YYYY/MM/DD") + "-" + dayjs(v2).format("YYYY/MM/DD");
    }

    conditionValue2.push(v);
  } else if (conditionName == "duplicateValue") {
    let v = conditionValue[0];

    if (v != "0" || v != "1") {
      return tooltip.info("The conditionValue parameter is invalid.", "");
    }

    conditionValue2.push(v);
  } else if (
    conditionName == "top10" ||
    conditionName == "top10%" ||
    conditionName == "last10" ||
    conditionName == "last10%"
  ) {
    let v = conditionValue[0];

    if (parseInt(v) != v || parseInt(v) < 1 || parseInt(v) > 1000) {
      conditionformat.infoDialog(conditionformat_Text.pleaseEnterInteger, "");
      return;
    }

    conditionValue2.push(parseInt(v));
  } else if (conditionName == "AboveAverage" || conditionName == "SubAverage") {
    conditionValue2.push(conditionName);
  }

  if (
    !format.hasOwnProperty("textColor") ||
    !format.hasOwnProperty("cellColor")
  ) {
    return tooltip.info("The format parameter is invalid.", "");
  }

  if (getObjType(cellrange) == "string") {
    cellrange = conditionformat.getRangeByTxt(cellrange);
  } else if (getObjType(cellrange) == "object") {
    cellrange = [cellrange];
  }

  if (getObjType(cellrange) != "array") {
    return tooltip.info("The cellrange parameter is invalid.", "");
  }

  let rule = {
    type: "default",
    cellrange: cellrange,
    format: format,
    conditionName: conditionName,
    conditionRange: conditionRange,
    conditionValue: conditionValue2,
  };

  //保存之前的规则
  let fileH = $.extend(true, [], Store.luckysheetfile);
  let historyRules = conditionformat.getHistoryRules(fileH);

  //保存当前的规则
  let ruleArr = file["luckysheet_conditionformat_save"] || [];
  ruleArr.push(rule);
  file["luckysheet_conditionformat_save"] = ruleArr;

  let fileC = $.extend(true, [], Store.luckysheetfile);
  let currentRules = conditionformat.getCurrentRules(fileC);

  //刷新一次表格
  conditionformat.ref(historyRules, currentRules);

  //发送给后台
  if (server.allowUpdate) {
    server.saveParam("all", file.index, ruleArr, {
      k: "luckysheet_conditionformat_save",
    });
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 为指定索引的工作表，选定的范围开启条件格式，返回开启条件格式后的数据。
 * @param {String} type 条件格式规则类型
 * @param {Object} options 可选参数
 * @param {Array | String} options.format 颜色设置
 * @param {Array | Object | String} options.cellrange 选区范围
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function setRangeConditionalFormat(type, options = {}) {
  let typeValues = ["dataBar", "colorGradation", "icons"];

  if (!type || !typeValues.includes(type)) {
    return tooltip.info("The type parameter is invalid.", "");
  }

  let {
    format,
    cellrange = Store.luckysheet_select_save,
    order = getSheetIndex(Store.currentSheetIndex),
    success,
  } = { ...options };

  cellrange = JSON.parse(JSON.stringify(cellrange));
  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("Incorrect worksheet index", "");
  }

  if (type == "dataBar") {
    if (format == null) {
      format = ["#638ec6", "#ffffff"];
    }

    if (
      getObjType(format) != "array" ||
      format.length < 1 ||
      format.length > 2
    ) {
      return tooltip.info("The format parameter is invalid.", "");
    }
  } else if (type == "colorGradation") {
    if (format == null) {
      format = [
        "rgb(99, 190, 123)",
        "rgb(255, 235, 132)",
        "rgb(248, 105, 107)",
      ];
    }

    if (
      getObjType(format) != "array" ||
      format.length < 2 ||
      format.length > 3
    ) {
      return tooltip.info("The format parameter is invalid.", "");
    }
  } else if (type == "icons") {
    if (format == null) {
      format = "threeWayArrowMultiColor";
    }

    let formatValues = [
      "threeWayArrowMultiColor",
      "threeTriangles",
      "fourWayArrowMultiColor",
      "fiveWayArrowMultiColor",
      "threeWayArrowGrayColor",
      "fourWayArrowGrayColor",
      "fiveWayArrowGrayColor",
      "threeColorTrafficLightRimless",
      "threeSigns",
      "greenRedBlackGradient",
      "threeColorTrafficLightBordered",
      "fourColorTrafficLight",
      "threeSymbolsCircled",
      "tricolorFlag",
      "threeSymbolsnoCircle",
      "threeStars",
      "fiveQuadrantDiagram",
      "fiveBoxes",
      "grade4",
      "grade5",
    ];

    if (getObjType(format) != "string" || !formatValues.includes(format)) {
      return tooltip.info("The format parameter is invalid.", "");
    }

    switch (format) {
      case "threeWayArrowMultiColor":
        format = {
          len: 3,
          leftMin: 0,
          top: 0,
        };
        break;
      case "threeTriangles":
        format = {
          len: 3,
          leftMin: 0,
          top: 1,
        };
        break;
      case "fourWayArrowMultiColor":
        format = {
          len: 4,
          leftMin: 0,
          top: 2,
        };
        break;
      case "fiveWayArrowMultiColor":
        format = {
          len: 5,
          leftMin: 0,
          top: 3,
        };
        break;
      case "threeWayArrowGrayColor":
        format = {
          len: 3,
          leftMin: 5,
          top: 0,
        };
        break;
      case "fourWayArrowGrayColor":
        format = {
          len: 4,
          leftMin: 5,
          top: 1,
        };
        break;
      case "fiveWayArrowGrayColor":
        format = {
          len: 5,
          leftMin: 5,
          top: 2,
        };
        break;
      case "threeColorTrafficLightRimless":
        format = {
          len: 3,
          leftMin: 0,
          top: 4,
        };
        break;
      case "threeSigns":
        format = {
          len: 3,
          leftMin: 0,
          top: 5,
        };
        break;
      case "greenRedBlackGradient":
        format = {
          len: 4,
          leftMin: 0,
          top: 6,
        };
        break;
      case "threeColorTrafficLightBordered":
        format = {
          len: 3,
          leftMin: 5,
          top: 4,
        };
        break;
      case "fourColorTrafficLight":
        format = {
          len: 4,
          leftMin: 5,
          top: 5,
        };
        break;
      case "threeSymbolsCircled":
        format = {
          len: 3,
          leftMin: 0,
          top: 7,
        };
        break;
      case "tricolorFlag":
        format = {
          len: 3,
          leftMin: 0,
          top: 8,
        };
        break;
      case "threeSymbolsnoCircle":
        format = {
          len: 3,
          leftMin: 5,
          top: 7,
        };
        break;
      case "threeStars":
        format = {
          len: 3,
          leftMin: 0,
          top: 9,
        };
        break;
      case "fiveQuadrantDiagram":
        format = {
          len: 5,
          leftMin: 0,
          top: 10,
        };
        break;
      case "fiveBoxes":
        format = {
          len: 5,
          leftMin: 0,
          top: 11,
        };
        break;
      case "grade4":
        format = {
          len: 4,
          leftMin: 5,
          top: 9,
        };
        break;
      case "grade5":
        format = {
          len: 5,
          leftMin: 5,
          top: 10,
        };
        break;
    }
  }

  if (getObjType(cellrange) == "string") {
    cellrange = conditionformat.getRangeByTxt(cellrange);
  } else if (getObjType(cellrange) == "object") {
    cellrange = [cellrange];
  }

  if (getObjType(cellrange) != "array") {
    return tooltip.info("The cellrange parameter is invalid.", "");
  }

  let rule = {
    type: type,
    cellrange: cellrange,
    format: format,
  };

  //保存之前的规则
  let fileH = $.extend(true, [], Store.luckysheetfile);
  let historyRules = conditionformat.getHistoryRules(fileH);

  //保存当前的规则
  let ruleArr = file["luckysheet_conditionformat_save"] || [];
  ruleArr.push(rule);
  file["luckysheet_conditionformat_save"] = ruleArr;

  let fileC = $.extend(true, [], Store.luckysheetfile);
  let currentRules = conditionformat.getCurrentRules(fileC);

  //刷新一次表格
  conditionformat.ref(historyRules, currentRules);

  //发送给后台
  if (server.allowUpdate) {
    server.saveParam("all", file.index, ruleArr, {
      k: "luckysheet_conditionformat_save",
    });
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 为指定下标的工作表，删除条件格式规则，返回被删除的条件格式规则
 * @param {Number} itemIndex 条件格式规则索引
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 * @param {Function} options.success 操作结束的回调函数
 */
export function deleteRangeConditionalFormat(itemIndex, options = {}) {
  if (!isRealNum(itemIndex)) {
    return tooltip.info("The itemIndex parameter is invalid.", "");
  }

  itemIndex = Number(itemIndex);

  let { order = getSheetIndex(Store.currentSheetIndex), success } = {
    ...options,
  };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  let cdformat = $.extend(true, [], file.luckysheet_conditionformat_save);

  if (cdformat.length == 0) {
    return tooltip.info(
      "This worksheet has no conditional format to delete",
      ""
    );
  } else if (cdformat[itemIndex] == null) {
    return tooltip.info(
      "The conditional format of the index cannot be found",
      ""
    );
  }

  let cdformatItem = cdformat.splice(itemIndex, 1);

  //保存之前的规则
  let fileH = $.extend(true, [], Store.luckysheetfile);
  let historyRules = conditionformat.getHistoryRules(fileH);

  //保存当前的规则
  file["luckysheet_conditionformat_save"] = cdformat;

  let fileC = $.extend(true, [], Store.luckysheetfile);
  let currentRules = conditionformat.getCurrentRules(fileC);

  //刷新一次表格
  conditionformat.ref(historyRules, currentRules);

  //发送给后台
  if (server.allowUpdate) {
    server.saveParam("all", file.index, ruleArr, {
      k: "luckysheet_conditionformat_save",
    });
  }

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 1);

  return cdformatItem;
}

/**
 * 清除指定工作表指定单元格区域的内容，不同于删除选区的功能，不需要设定单元格移动情况
 * @param {Object} options 可选参数
 * @param {Array | Object | String} options.range 要清除的选区范围
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 * @param {Function} options.success 操作结束的回调函数
 */
export function clearRange(options = {}) {
  let {
    range = Store.luckysheet_select_save,
    order = getSheetIndex(Store.currentSheetIndex),
    success,
  } = { ...options };

  range = JSON.parse(JSON.stringify(range));
  if (getObjType(range) == "string") {
    if (!formula.iscelldata(range)) {
      return tooltip.info("The range parameter is invalid.", "");
    }

    let cellrange = formula.getcellrange(range);
    range = [
      {
        row: cellrange.row,
        column: cellrange.column,
      },
    ];
  } else if (getObjType(range) == "object") {
    if (range.row == null || range.column == null) {
      return tooltip.info("The range parameter is invalid.", "");
    }

    range = [
      {
        row: range.row,
        column: range.column,
      },
    ];
  }

  if (getObjType(range) != "array") {
    return tooltip.info("The range parameter is invalid.", "");
  }

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  let cfg = $.extend(true, {}, file.config);
  let has_PartMC = false;

  for (let s = 0; s < range.length; s++) {
    let r1 = range[s].row[0],
      r2 = range[s].row[1];
    let c1 = range[s].column[0],
      c2 = range[s].column[1];

    has_PartMC = hasPartMC(cfg, r1, r2, c1, c2);

    if (has_PartMC) {
      break;
    }
  }

  if (has_PartMC) {
    return tooltip.info(
      "Cannot perform this operation on partially merged cells",
      ""
    );
  }

  let d = $.extend(true, [], file.data);

  if (d.length == 0) {
    d = $.extend(true, [], sheetmanage.buildGridData(file));
  }

  for (let s = 0; s < range.length; s++) {
    let r1 = range[s].row[0],
      r2 = range[s].row[1];
    let c1 = range[s].column[0],
      c2 = range[s].column[1];

    for (let r = r1; r <= r2; r++) {
      for (let c = c1; c <= c2; c++) {
        let cell = d[r][c];

        if (getObjType(cell) == "object") {
          delete cell["m"];
          delete cell["v"];

          if (cell["f"] != null) {
            delete cell["f"];
            formula.delFunctionGroup(r, c, file.index);

            delete cell["spl"];
          }

          if (cell["ct"] != null && cell["ct"].t == "inlineStr") {
            delete cell["ct"];
          }
        } else {
          d[r][c] = null;
        }
      }
    }
  }

  if (file.index == Store.currentSheetIndex) {
    jfrefreshgrid(d, range);
  } else {
    file.data = d;
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 删除指定工作表指定单元格区域，返回删除掉的数据，同时，指定是右侧单元格左移还是下方单元格上移
 * @param {String} move 删除后，单元格左移/上移
 * @param {Object} options 可选参数
 * @param {Object | String} options.range 要删除的选区范围
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 * @param {Function} options.success 操作结束的回调函数
 */
export function deleteRange(move, options = {}) {
  let moveList = ["left", "up"];

  if (!moveList.includes(move)) {
    return tooltip.info("The move parameter is invalid.", "");
  }

  let {
    range = Store.luckysheet_select_save[
      Store.luckysheet_select_save.length - 1
    ],
    order = getSheetIndex(Store.currentSheetIndex),
    success,
  } = { ...options };

  if (getObjType(range) == "string") {
    if (!formula.iscelldata(range)) {
      return tooltip.info("The range parameter is invalid.", "");
    }

    let cellrange = formula.getcellrange(range);
    range = {
      row: cellrange.row,
      column: cellrange.column,
    };
  }

  if (
    getObjType(range) != "object" ||
    range.row == null ||
    range.column == null
  ) {
    return tooltip.info("The range parameter is invalid.", "");
  }

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  let str = range.row[0],
    edr = range.row[1],
    stc = range.column[0],
    edc = range.column[1];

  if (move == "left") {
    luckysheetDeleteCell("moveLeft", str, edr, stc, edc, order);
  } else if (move == "up") {
    luckysheetDeleteCell("moveUp", str, edr, stc, edc, order);
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 指定工作表指定单元格区域的数据进行矩阵操作，返回操作成功后的结果数据
 * @param {String} type 矩阵操作的类型
 * @param {Object} options 可选参数
 * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]}，只能为单个选区；默认为当前选区
 * @param {Function} options.success 操作结束的回调函数
 */
export function matrixOperation(type, options = {}) {
  let typeValues = [
    "flipUpDown", // 上下翻转
    "flipLeftRight", // 左右翻转
    "flipClockwise", // 顺时针旋转
    "flipCounterClockwise", // 逆时针旋转
    "transpose", // 转置
    "deleteZeroByRow", // 按行删除两端0值
    "deleteZeroByColumn", // 按列删除两端0值
    "removeDuplicateByRow", // 按行删除重复值
    "removeDuplicateByColumn", // 按列删除重复值
    "newMatrix", // 生产新矩阵
  ];

  if (!type || typeValues.indexOf(type) < 0) {
    return tooltip.info("The type parameter is invalid.", "");
  }

  let curRange = Store.luckysheet_select_save[0];
  let { range = curRange, success } = { ...options };

  if (range instanceof Array && range.length > 1) {
    tooltip.info(locale().drag.noMulti, "");
    return;
  }

  if (range && typeof range === "string" && formula.iscelldata(range)) {
    range = formula.getcellrange(range);
  }

  let getdata = getdatabyselection(range);
  let arr = [];
  if (getdata.length === 0) {
    return;
  }

  let getdatalen, collen, arr1;
  switch (type) {
    case "flipUpDown":
      for (let r = getdata.length - 1; r >= 0; r--) {
        let a = [];
        for (let c = 0; c < getdata[0].length; c++) {
          let value = "";
          if (getdata[r] != null && getdata[r][c] != null) {
            value = getdata[r][c];
          }
          a.push(value);
        }
        arr.push(a);
      }
      break;
    case "flipLeftRight":
      for (let r = 0; r < getdata.length; r++) {
        let a = [];
        for (let c = getdata[0].length - 1; c >= 0; c--) {
          let value = "";
          if (getdata[r] != null && getdata[r][c] != null) {
            value = getdata[r][c];
          }
          a.push(value);
        }
        arr.push(a);
      }
      break;
    case "flipClockwise":
      for (let c = 0; c < getdata[0].length; c++) {
        let a = [];
        for (let r = getdata.length - 1; r >= 0; r--) {
          let value = "";
          if (getdata[r] != null && getdata[r][c] != null) {
            value = getdata[r][c];
          }
          a.push(value);
        }
        arr.push(a);
      }
      break;
    case "flipCounterClockwise":
      for (let c = getdata[0].length - 1; c >= 0; c--) {
        let a = [];
        for (let r = 0; r < getdata.length; r++) {
          let value = "";
          if (getdata[r] != null && getdata[r][c] != null) {
            value = getdata[r][c];
          }
          a.push(value);
        }
        arr.push(a);
      }
      break;
    case "transpose":
      for (let c = 0; c < getdata[0].length; c++) {
        let a = [];
        for (let r = 0; r < getdata.length; r++) {
          let value = "";
          if (getdata[r] != null && getdata[r][c] != null) {
            value = getdata[r][c];
          }
          a.push(value);
        }
        arr.push(a);
      }
      break;
    case "deleteZeroByRow":
      getdatalen = getdata[0].length;
      for (let r = 0; r < getdata.length; r++) {
        let a = [],
          stdel = true,
          eddel = true;
        for (let c = 0; c < getdatalen; c++) {
          let value = "";
          if (getdata[r] != null && getdata[r][c] != null) {
            value = getdata[r][c];
            if ((value.v == "0" || value.v == 0) && stdel) {
              continue;
            } else {
              stdel = false;
            }
          }
          a.push(value);
        }

        let a1 = [];
        if (a.length == getdatalen) {
          a1 = a;
        } else {
          for (let c = a.length - 1; c >= 0; c--) {
            let value = "";
            if (a[c] != null) {
              value = a[c];
              if ((value.v == "0" || value.v == 0) && eddel) {
                continue;
              } else {
                eddel = false;
              }
            }
            a1.unshift(value);
          }

          let l = getdatalen - a1.length;
          for (let c1 = 0; c1 < l; c1++) {
            a1.push("");
          }
        }
        arr.push(a1);
      }
      break;
    case "deleteZeroByColumn":
      getdatalen = getdata.length;
      collen = getdata[0].length;
      for (let c = 0; c < collen; c++) {
        let a = [],
          stdel = true,
          eddel = true;
        for (let r = 0; r < getdatalen; r++) {
          let value = "";
          if (getdata[r] != null && getdata[r][c] != null) {
            value = getdata[r][c];
            if ((value.v == "0" || value.v == 0) && stdel) {
              continue;
            } else {
              stdel = false;
            }
          }
          a.push(value);
        }

        let a1 = [];
        if (a.length == getdatalen) {
          a1 = a;
        } else {
          for (let r = a.length - 1; r >= 0; r--) {
            let value = "";
            if (a[r] != null) {
              value = a[r];
              if ((value.v == "0" || value.v == 0) && eddel) {
                continue;
              } else {
                eddel = false;
              }
            }
            a1.unshift(value);
          }

          let l = getdatalen - a1.length;
          for (let r1 = 0; r1 < l; r1++) {
            a1.push("");
          }
        }
        arr.push(a1);
      }

      arr1 = [];
      for (let c = 0; c < arr[0].length; c++) {
        let a = [];
        for (let r = 0; r < arr.length; r++) {
          let value = "";
          if (arr[r] != null && arr[r][c] != null) {
            value = arr[r][c];
          }
          a.push(value);
        }
        arr1.push(a);
      }
      break;
    case "removeDuplicateByRow":
      getdatalen = getdata[0].length;
      for (let r = 0; r < getdata.length; r++) {
        let a = [],
          repeat = {};

        for (let c = 0; c < getdatalen; c++) {
          let value = null;
          if (getdata[r] != null && getdata[r][c] != null) {
            value = getdata[r][c];

            if (value.v in repeat) {
              repeat[value.v].push(value);
            } else {
              repeat[value.v] = [];
              repeat[value.v].push(value);
            }
          }
        }

        for (let c = 0; c < getdatalen; c++) {
          let value = null;
          if (getdata[r] != null && getdata[r][c] != null) {
            value = getdata[r][c];

            if (repeat[value.v].length == 1) {
              a.push(value);
            }
          }
        }

        let l = getdatalen - a.length;
        for (let c1 = 0; c1 < l; c1++) {
          a.push(null);
        }
        arr.push(a);
      }
      break;
    case "removeDuplicateByColumn":
      collen = getdata[0].length;
      getdatalen = getdata.length;
      for (let c = 0; c < collen; c++) {
        let a = [],
          repeat = {};

        for (let r = 0; r < getdatalen; r++) {
          let value = null;
          if (getdata[r] != null && getdata[r][c] != null) {
            value = getdata[r][c];

            if (value.v in repeat) {
              repeat[value.v].push(value);
            } else {
              repeat[value.v] = [];
              repeat[value.v].push(value);
            }
          }
        }

        for (let r = 0; r < getdatalen; r++) {
          let value = null;
          if (getdata[r] != null && getdata[r][c] != null) {
            value = getdata[r][c];

            if (repeat[value.v].length == 1) {
              a.push(value);
            }
          }
        }

        a1 = a;
        let l = getdatalen - a1.length;
        for (let r1 = 0; r1 < l; r1++) {
          a1.push(null);
        }
        arr.push(a1);
      }

      arr1 = [];
      for (let c = 0; c < arr[0].length; c++) {
        let a = [];
        for (let r = 0; r < arr.length; r++) {
          let value = null;
          if (arr[r] != null && arr[r][c] != null) {
            value = arr[r][c];
          }
          a.push(value);
        }
        arr1.push(a);
      }
      break;
    case "newMatrix":
      // TODO
      console.log("TODO");
      break;
  }
  editor.controlHandler(arr, range);

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 指定工作表指定单元格区域的数据进行矩阵计算，返回计算成功后的结果数据
 * @param {String} type 计算方式
 * @param {Number} number 计算数值
 * @param {Object} options 可选参数
 * @param {Object | String} options.range 选区范围,支持选区的格式为"A1:B2"、"sheetName!A1:B2"或者{row:[0,1],column:[0,1]}，只能为单个选区；默认为当前选区
 * @param {Function} options.success 操作结束的回调函数
 */
export function matrixCalculation(type, number, options = {}) {
  let typeValues = [
    "plus", // 加
    "minus", // 减
    "multiply", // 乘
    "divided", // 除
    "power", // 幂
    "root", // 次方根
    "log", // 对数log
  ];

  if (!type || typeValues.indexOf(type) < 0) {
    return tooltip.info("The type parameter is invalid.", "");
  }

  if (!isRealNum(number)) {
    return tooltip.info("The number parameter is invalid.", "");
  }

  let curRange = Store.luckysheet_select_save[0];
  let { range = curRange, success } = { ...options };

  if (range instanceof Array && range.length > 1) {
    tooltip.info(locale().drag.noMulti, "");
    return;
  }

  if (range && typeof range === "string" && formula.iscelldata(range)) {
    range = formula.getcellrange(range);
  }

  let getdata = getdatabyselection(range);
  if (getdata.length == 0) {
    return;
  }

  let arr = [];
  for (let r = 0; r < getdata.length; r++) {
    let a = [];
    for (let c = 0; c < getdata[0].length; c++) {
      let value = "";
      if (getdata[r] != null && getdata[r][c] != null) {
        value = getdata[r][c];
        if (
          parseInt(value) != null &&
          getdata[r][c].ct != undefined &&
          getdata[r][c].ct.t == "n"
        ) {
          if (type == "minus") {
            value.v = value.v - number;
          } else if (type == "multiply") {
            value.v = value.v * number;
          } else if (type == "divided") {
            value.v = numFormat(value.v / number, 4);
          } else if (type == "power") {
            value.v = Math.pow(value.v, number);
          } else if (type == "root") {
            if (number == 2) {
              value.v = numFormat(Math.sqrt(value.v), 4);
            } else if (number == 3 && Math.cbrt) {
              value.v = numFormat(Math.cbrt(value.v), 4);
            } else {
              value.v = numFormat(jfnqrt(value.v, number), 4);
            }
          } else if (type == "log") {
            value.v = numFormat(
              (Math.log(value.v) * 10000) / Math.log(Math.abs(number)),
              4
            );
          } else {
            value.v = value.v + number;
          }

          if (value.v == null) {
            value.m = "";
          } else {
            value.m = value.v.toString();
          }
        }
      }
      a.push(value);
    }
    arr.push(a);
  }

  editor.controlHandler(arr, range);

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 新增一个sheet，返回新增的工作表对象
 * @param {Object} options 可选参数
 * @param {Object} options.sheetObject 新增的工作表的数据；默认值为空对象
 * @param {Number} options.order 新增的工作表索引；默认值为最后一个索引位置
 * @param {Function} options.success 操作结束的回调函数
 */
export function setSheetAdd(options = {}) {
  let lastOrder = Store.luckysheetfile.length - 1;
  let { sheetObject = {}, order = lastOrder, success } = { ...options };

  if (!isRealNum(order)) {
    return tooltip.info("Parameter is not a table index", "");
  }

  order = Number(order);

  let index = sheetmanage.generateRandomSheetIndex();
  // calcChain公式链里的index也要跟着变化
  if (sheetObject.calcChain && sheetObject.calcChain.length > 0) {
    sheetObject.calcChain.forEach((item) => {
      item.index = index;
    });
  }
  let sheetname = sheetmanage.generateRandomSheetName(
    Store.luckysheetfile,
    false
  );
  if (!!sheetObject.name) {
    let sameName = false;

    for (let i = 0; i < Store.luckysheetfile.length; i++) {
      if (Store.luckysheetfile[i].name == sheetObject.name) {
        sameName = true;
        break;
      }
    }

    if (!sameName) {
      sheetname = sheetObject.name;
    }
  }

  $("#luckysheet-sheet-container-c").append(
    replaceHtml(sheetHTML, {
      index: index,
      active: "",
      name: sheetname,
      style: "",
      colorset: "",
    })
  );

  let sheetconfig = {
    name: "",
    color: "",
    status: "0",
    order: "",
    index: "",
    celldata: [],
    row: Store.defaultrowNum,
    column: Store.defaultcolumnNum,
    config: {},
    pivotTable: null,
    isPivotTable: false,
  };
  sheetconfig = $.extend(true, sheetconfig, sheetObject);

  sheetconfig.index = index;
  sheetconfig.name = sheetname;
  sheetconfig.order = order;

  if (order <= 0) {
    let beforeIndex = Store.luckysheetfile[0].index;
    let beforeObj = $("#luckysheet-sheets-item" + beforeIndex);
    $("#luckysheet-sheets-item" + index).insertBefore(beforeObj);

    Store.luckysheetfile.splice(0, 0, sheetconfig);
  } else {
    if (order > Store.luckysheetfile.length) {
      order = Store.luckysheetfile.length;
    }

    let afterIndex = Store.luckysheetfile[order - 1].index;
    let afterObj = $("#luckysheet-sheets-item" + afterIndex);
    $("#luckysheet-sheets-item" + index).insertAfter(afterObj);

    Store.luckysheetfile.splice(order, 0, sheetconfig);
  }

  let orders = {};

  Store.luckysheetfile.forEach((item, i, arr) => {
    arr[i].order = i;
    orders[item.index.toString()] = i;
  });

  $("#luckysheet-sheet-area div.luckysheet-sheets-item").removeClass(
    "luckysheet-sheets-item-active"
  );
  $("#luckysheet-sheets-item" + index).addClass(
    "luckysheet-sheets-item-active"
  );
  $("#luckysheet-cell-main").append(
    '<div id="luckysheet-datavisual-selection-set-' +
      index +
      '" class="luckysheet-datavisual-selection-set"></div>'
  );
  cleargridelement(true);

  server.saveParam("sha", null, $.extend(true, {}, sheetconfig));
  server.saveParam("shr", null, orders);

  if (Store.clearjfundo) {
    Store.jfundo.length = 0;
    let redo = {};
    redo["type"] = "addSheet";
    redo["sheetconfig"] = $.extend(true, {}, sheetconfig);
    redo["index"] = index;
    redo["currentSheetIndex"] = Store.currentSheetIndex;
    Store.jfredo.push(redo);
  }

  sheetmanage.changeSheetExec(index, false, true);

  if (success && typeof success === "function") {
    success();
  }
  return sheetconfig;
}

/**
 * 删除指定下标的工作表，返回已删除的工作表对象
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 * @param {Function} options.success 操作结束的回调函数
 */
export function setSheetDelete(options = {}) {
  let { order = getSheetIndex(Store.currentSheetIndex), success } = {
    ...options,
  };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  if (Store.luckysheetfile.length === 1) {
    return tooltip.info(locale().sheetconfig.noMoreSheet, "");
  }

  sheetmanage.deleteSheet(file.index);

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 1);

  return file;
}

/**
 * 复制指定下标的工作表到指定下标位置
 * @param {Object} options 可选参数
 * @param {Number} options.targetOrder 新复制的工作表目标下标位置；默认值为当前工作表下标的下一个下标位置（递增）
 * @param {Number} options.order 被复制的工作表下标；默认值为当前工作表下标
 * @param {Function} options.success 操作结束的回调函数
 */
export function setSheetCopy(options = {}) {
  let {
    targetOrder,
    order = getSheetIndex(Store.currentSheetIndex),
    success,
  } = { ...options };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  if (targetOrder == null) {
    targetOrder = order + 1;
  }

  if (!isRealNum(targetOrder)) {
    return tooltip.info("The targetOrder parameter is invalid.", "");
  }

  let copyindex = file.index;
  let index = sheetmanage.generateRandomSheetIndex();

  let copyjson = $.extend(true, {}, file);
  copyjson.order = Store.luckysheetfile.length;
  copyjson.index = index;
  copyjson.name = sheetmanage.generateCopySheetName(
    Store.luckysheetfile,
    copyjson.name
  );

  let colorset = "";
  if (copyjson.color != null) {
    colorset =
      '<div class="luckysheet-sheets-item-color" style=" position: absolute; width: 100%; height: 3px; bottom: 0px; left: 0px; background-color: ' +
      copyjson.color +
      ';"></div>';
  }

  let afterObj = $("#luckysheet-sheets-item" + copyindex);
  if (isRealNum(targetOrder)) {
    afterObj = $(
      "#luckysheet-sheets-item" + Store.luckysheetfile[targetOrder - 1].index
    );
  }

  $("#luckysheet-sheet-container-c").append(
    replaceHtml(sheetHTML, {
      index: copyjson.index,
      active: "",
      name: copyjson.name,
      order: copyjson.order,
      style: "",
      colorset: colorset,
    })
  );
  $("#luckysheet-sheets-item" + copyjson.index).insertAfter(afterObj);
  Store.luckysheetfile.splice(targetOrder, 0, copyjson);

  $("#luckysheet-sheet-area div.luckysheet-sheets-item").removeClass(
    "luckysheet-sheets-item-active"
  );
  $("#luckysheet-sheets-item" + index).addClass(
    "luckysheet-sheets-item-active"
  );
  $("#luckysheet-cell-main").append(
    '<div id="luckysheet-datavisual-selection-set-' +
      index +
      '" class="luckysheet-datavisual-selection-set"></div>'
  );
  cleargridelement(true);

  server.saveParam("shc", index, { copyindex: copyindex, name: copyjson.name });

  sheetmanage.changeSheetExec(index);
  sheetmanage.reOrderAllSheet();

  if (Store.clearjfundo) {
    Store.jfredo.push({
      type: "copySheet",
      copyindex: copyindex,
      index: copyjson.index,
      sheetIndex: copyjson.index,
    });
  } else if (Store.jfredo.length > 0) {
    let jfredostr = Store.jfredo[Store.jfredo.length - 1];

    if (jfredostr.type == "copySheet") {
      jfredostr.index = copyjson.index;
      jfredostr.sheetIndex = copyjson.index;
    }
  }

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 1);

  return copyjson;
}

/**
 * 隐藏指定下标的工作表，返回被隐藏的工作表对象
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 * @param {Function} options.success 操作结束的回调函数
 */
export function setSheetHide(options = {}) {
  let { order = getSheetIndex(Store.currentSheetIndex), success } = {
    ...options,
  };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  sheetmanage.setSheetHide(file.index);

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 1);

  return file;
}

/**
 * 取消隐藏指定下标的工作表，返回被取消隐藏的工作表对象
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 * @param {Function} options.success 操作结束的回调函数
 */
export function setSheetShow(options = {}) {
  let { order = getSheetIndex(Store.currentSheetIndex), success } = {
    ...options,
  };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  sheetmanage.setSheetShow(file.index);

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 1);

  return file;
}

/**
 * 设置指定下标的工作表为当前工作表（激活态），即切换到指定的工作表，返回被激活的工作表对象
 * @param {Number} order 要激活的工作表下标
 * @param {Object} options 可选参数
 * @param {Function} options.success 操作结束的回调函数
 */
export function setSheetActive(order, options = {}) {
  if (
    order == null ||
    !isRealNum(order) ||
    Store.luckysheetfile[order] == null
  ) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  let file = Store.luckysheetfile[order];

  let { success } = { ...options };

  $("#luckysheet-sheet-area div.luckysheet-sheets-item").removeClass(
    "luckysheet-sheets-item-active"
  );
  $("#luckysheet-sheets-item" + file.index).addClass(
    "luckysheet-sheets-item-active"
  );

  sheetmanage.changeSheet(file.index);

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 1);
  server.multipleRangeShow();
  return file;
}

/**
 * 修改工作表名称
 * @param {String} name 工作表名称
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 * @param {Function} options.success 操作结束的回调函数
 */
export function setSheetName(name, options = {}) {
  if (getObjType(name) != "string" || name.toString().length == 0) {
    return tooltip.info("The name parameter is invalid.", "");
  }

  let { order = getSheetIndex(Store.currentSheetIndex), success } = {
    ...options,
  };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  let oldtxt = file.name;
  file.name = name;

  $(
    "#luckysheet-sheets-item" + file.index + " .luckysheet-sheets-item-name"
  ).text(name);

  server.saveParam("all", file.index, name, { k: "name" });

  if (Store.clearjfundo) {
    let redo = {};
    redo["type"] = "sheetName";
    redo["sheetIndex"] = file.index;

    redo["oldtxt"] = oldtxt;
    redo["txt"] = name;

    Store.jfundo.length = 0;
    Store.jfredo.push(redo);
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 设置工作表名称处的颜色
 * @param {String} color 工作表颜色
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 * @param {Function} options.success 操作结束的回调函数
 */
export function setSheetColor(color, options = {}) {
  if (getObjType(color) != "string" || color.toString().length == 0) {
    return tooltip.info("The color parameter is invalid.", "");
  }

  let { order = getSheetIndex(Store.currentSheetIndex), success } = {
    ...options,
  };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  let oldcolor = file.color;
  file.color = color;

  $("#luckysheet-sheets-item" + file.index)
    .find(".luckysheet-sheets-item-color")
    .remove();
  $("#luckysheet-sheets-item" + file.index).append(
    '<div class="luckysheet-sheets-item-color" style=" position: absolute; width: 100%; height: 3px; bottom: 0px; left: 0px; background-color: ' +
      color +
      ';"></div>'
  );

  server.saveParam("all", file.index, color, { k: "color" });

  if (Store.clearjfundo) {
    let redo = {};
    redo["type"] = "sheetColor";
    redo["sheetIndex"] = file.index;

    redo["oldcolor"] = oldcolor;
    redo["color"] = color;

    Store.jfundo.length = 0;
    Store.jfredo.push(redo);
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 指定工作表向左边或右边移动一个位置，或者指定索引，返回指定的工作表对象
 * @param {String | Number} type 工作表移动方向或者移动的目标索引
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表索引；默认值为当前工作表索引
 * @param {Function} options.success 操作结束的回调函数
 */
export function setSheetMove(type, options = {}) {
  if (type != "left" && type != "right" && !isRealNum(type)) {
    return tooltip.info("Type parameter not available", "");
  }

  if (isRealNum(type)) {
    type = parseInt(type);
  }

  let curOrder = getSheetIndex(Store.currentSheetIndex);
  let { order = curOrder, success } = { ...options };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("ncorrect worksheet index", "");
  }

  let sheetIndex = file.index;

  if (type == "left") {
    if (order == 0) {
      return;
    }

    let prevIndex = Store.luckysheetfile[order - 1].index;
    $("#luckysheet-sheets-item" + sheetIndex).insertBefore(
      $("#luckysheet-sheets-item" + prevIndex)
    );

    Store.luckysheetfile.splice(order, 1);
    Store.luckysheetfile.splice(order - 1, 0, file);
  } else if (type == "right") {
    if (order == Store.luckysheetfile.length - 1) {
      return;
    }

    let nextIndex = Store.luckysheetfile[order + 1].index;
    $("#luckysheet-sheets-item" + sheetIndex).insertAfter(
      $("#luckysheet-sheets-item" + nextIndex)
    );

    Store.luckysheetfile.splice(order, 1);
    Store.luckysheetfile.splice(order + 1, 0, file);
  } else {
    if (type < 0) {
      type = 0;
    }

    if (type > Store.luckysheetfile.length - 1) {
      type = Store.luckysheetfile.length - 1;
    }

    if (type == order) {
      return;
    }

    if (type < order) {
      let prevIndex = Store.luckysheetfile[type].index;
      $("#luckysheet-sheets-item" + sheetIndex).insertBefore(
        $("#luckysheet-sheets-item" + prevIndex)
      );
    } else {
      let nextIndex = Store.luckysheetfile[type].index;
      $("#luckysheet-sheets-item" + sheetIndex).insertAfter(
        $("#luckysheet-sheets-item" + nextIndex)
      );
    }

    Store.luckysheetfile.splice(order, 1);
    Store.luckysheetfile.splice(type, 0, file);
  }

  let orders = {};

  Store.luckysheetfile.forEach((item, i, arr) => {
    arr[i].order = i;
    orders[item.index.toString()] = i;
  });

  server.saveParam("shr", null, orders);

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 重新排序所有工作表的位置，指定工作表顺序的数组。
 * @param {Array} orderList 工作表顺序，设置工作表的index和order来指定位置
 * @param {Object} options 可选参数
 * @param {Function} options.success 操作结束的回调函数
 */
export function setSheetOrder(orderList, options = {}) {
  if (orderList == null || orderList.length == 0) {
    return tooltip.info("Type orderList not available", "");
  }

  let orderListMap = {};
  orderList.forEach((item) => {
    orderListMap[item.index.toString()] = item.order;
  });

  Store.luckysheetfile.sort((x, y) => {
    let order_x = orderListMap[x.index.toString()];
    let order_y = orderListMap[y.index.toString()];

    if (order_x != null && order_y != null) {
      return order_x - order_y;
    } else if (order_x != null) {
      return -1;
    } else if (order_y != null) {
      return 1;
    } else {
      return 1;
    }
  });

  let orders = {};

  Store.luckysheetfile.forEach((item, i, arr) => {
    arr[i].order = i;
    orders[item.index.toString()] = i;

    if (i > 0) {
      let preIndex = arr[i - 1].index;
      $("#luckysheet-sheets-item" + item.index).insertAfter(
        $("#luckysheet-sheets-item" + preIndex)
      );
    }
  });

  server.saveParam("shr", null, orders);

  let { success } = { ...options };

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 设置工作表缩放比例
 * @param {Number} zoom 工作表缩放比例，值范围为0.1 ~ 4；
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 * @param {Function} options.success 操作结束的回调函数
 */
export function setSheetZoom(zoom, options = {}) {
  if (!isRealNum(zoom) || zoom < 0.1 || zoom > 4) {
    return tooltip.info("The zoom parameter is invalid.", "");
  }

  let { order = getSheetIndex(Store.currentSheetIndex), success } = {
    ...options,
  };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  file["zoomRatio"] = zoom;

  server.saveParam("all", file.index, zoom, { k: "zoomRatio" });

  if (file.index == Store.currentSheetIndex) {
    Store.zoomRatio = zoom;
    // 图片
    let currentSheet = sheetmanage.getSheetByIndex();
    imageCtrl.images = currentSheet.images;
    imageCtrl.allImagesShow();
    imageCtrl.init();

    zoomNumberDomBind();
    zoomRefreshView();
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 显示指定下标工作表的网格线，返回操作的工作表对象
 * @param {Object} options 可选参数
 * @param {Number} options.order 需要显示网格线的工作表下标；默认值为当前工作表下标
 * @param {Function} options.success 操作结束的回调函数
 */
export function showGridLines(options = {}) {
  let { order = getSheetIndex(Store.currentSheetIndex), success } = {
    ...options,
  };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  file.showGridLines = true;

  if (file.index == Store.currentSheetIndex) {
    Store.showGridLines = true;

    setTimeout(function() {
      luckysheetrefreshgrid();
    }, 1);
  }

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 1);

  return file;
}

/**
 * 隐藏指定下标工作表的网格线，返回操作的工作表对象
 * @param {Object} options 可选参数
 * @param {Number} options.order 需要显示网格线的工作表下标；默认值为当前工作表下标
 * @param {Function} options.success 操作结束的回调函数
 */
export function hideGridLines(options = {}) {
  let { order = getSheetIndex(Store.currentSheetIndex), success } = {
    ...options,
  };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  file.showGridLines = false;

  if (file.index == Store.currentSheetIndex) {
    Store.showGridLines = false;

    setTimeout(function() {
      luckysheetrefreshgrid();
    }, 1);
  }

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 1);

  return file;
}

/**
 * 刷新canvas
 * @param {Object} options 可选参数
 * @param {Function} options.success 操作结束的回调函数
 */
export function refresh(options = {}) {
  // luckysheetrefreshgrid();
  jfrefreshgrid();

  let { success } = { ...options };

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 滚动当前工作表位置
 * @param {Object} options 可选参数
 * @param {Number} options.scrollLeft 横向滚动值
 * @param {Number} options.scrollTop 纵向滚动值
 * @param {Number} options.targetRow 纵向滚动到指定的行号
 * @param {Number} options.targetColumn 横向滚动到指定的列号
 * @param {Function} options.success 操作结束的回调函数
 */
export function scroll(options = {}) {
  let { scrollLeft, scrollTop, targetRow, targetColumn, success } = {
    ...options,
  };

  if (scrollLeft != null) {
    if (!isRealNum(scrollLeft)) {
      return tooltip.info("The scrollLeft parameter is invalid.", "");
    }

    $("#luckysheet-scrollbar-x").scrollLeft(scrollLeft);
  } else if (targetColumn != null) {
    if (!isRealNum(targetColumn)) {
      return tooltip.info("The targetColumn parameter is invalid.", "");
    }

    let col = Store.visibledatacolumn[targetColumn],
      col_pre =
        targetColumn <= 0 ? 0 : Store.visibledatacolumn[targetColumn - 1];

    $("#luckysheet-scrollbar-x").scrollLeft(col_pre);
  }

  if (scrollTop != null) {
    if (!isRealNum(scrollTop)) {
      return tooltip.info("The scrollTop parameter is invalid.", "");
    }

    $("#luckysheet-scrollbar-y").scrollTop(scrollTop);
  } else if (targetRow != null) {
    if (!isRealNum(targetRow)) {
      return tooltip.info("The targetRow parameter is invalid.", "");
    }

    let row = Store.visibledatarow[targetRow],
      row_pre = targetRow <= 0 ? 0 : Store.visibledatarow[targetRow - 1];

    $("#luckysheet-scrollbar-y").scrollTop(row_pre);
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 根据窗口大小自动resize画布
 * @param {Object} options 可选参数
 * @param {Function} options.success 操作结束的回调函数
 */
export function resize(options = {}) {
  luckysheetsizeauto();

  let { success } = { ...options };

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 返回指定选区截图后生成的base64格式的图片
 * @param {Object} options 可选参数
 * @param {Object | String} options.range 选区范围，只能为单个选区；默认为当前选区
 */
export function getScreenshot(options = {}) {
  let {
    range = Store.luckysheet_select_save[
      Store.luckysheet_select_save.length - 1
    ],
  } = { ...options };

  if (getObjType(range) == "string") {
    if (!formula.iscelldata(range)) {
      return tooltip.info("The range parameter is invalid.", "");
    }

    let cellrange = formula.getcellrange(range);
    range = {
      row: cellrange.row,
      column: cellrange.column,
    };
  }

  if (
    getObjType(range) != "object" ||
    range.row == null ||
    range.column == null
  ) {
    return tooltip.info("The range parameter is invalid.", "");
  }

  let str = range.row[0],
    edr = range.row[1],
    stc = range.column[0],
    edc = range.column[1];

  let has_PartMC = hasPartMC(Store.config, str, edr, stc, edc);

  if (has_PartMC) {
    return tooltip.info(
      "Cannot perform this operation on partially merged cells",
      ""
    );
  }

  let visibledatarow = Store.visibledatarow;
  let visibledatacolumn = Store.visibledatacolumn;

  let scrollHeight, rh_height;
  if (str - 1 < 0) {
    scrollHeight = 0;
    rh_height = visibledatarow[edr];
  } else {
    scrollHeight = visibledatarow[str - 1];
    rh_height = visibledatarow[edr] - visibledatarow[str - 1];
  }

  let scrollWidth, ch_width;
  if (stc - 1 < 0) {
    scrollWidth = 0;
    ch_width = visibledatacolumn[edc];
  } else {
    scrollWidth = visibledatacolumn[stc - 1];
    ch_width = visibledatacolumn[edc] - visibledatacolumn[stc - 1];
  }

  let newCanvas = $("<canvas>")
    .attr({
      width: Math.ceil(ch_width * Store.devicePixelRatio),
      height: Math.ceil(rh_height * Store.devicePixelRatio),
    })
    .css({ width: ch_width, height: rh_height });

  luckysheetDrawMain(
    scrollWidth,
    scrollHeight,
    ch_width,
    rh_height,
    1,
    1,
    null,
    null,
    newCanvas
  );
  let ctx_newCanvas = newCanvas.get(0).getContext("2d");

  //补上 左边框和上边框
  ctx_newCanvas.beginPath();
  ctx_newCanvas.moveTo(0, 0);
  ctx_newCanvas.lineTo(0, Store.devicePixelRatio * rh_height);
  ctx_newCanvas.lineWidth = Store.devicePixelRatio * 2;
  ctx_newCanvas.strokeStyle = luckysheetdefaultstyle.strokeStyle;
  ctx_newCanvas.stroke();
  ctx_newCanvas.closePath();

  ctx_newCanvas.beginPath();
  ctx_newCanvas.moveTo(0, 0);
  ctx_newCanvas.lineTo(Store.devicePixelRatio * ch_width, 0);
  ctx_newCanvas.lineWidth = Store.devicePixelRatio * 2;
  ctx_newCanvas.strokeStyle = luckysheetdefaultstyle.strokeStyle;
  ctx_newCanvas.stroke();
  ctx_newCanvas.closePath();

  let url = newCanvas.get(0).toDataURL("image/png");

  return url;
}

/**
 * 设置工作簿名称
 * @param {String} name 工作簿名称
 * @param {Object} options 可选参数
 * @param {Function} options.success 操作结束的回调函数
 */
export function setWorkbookName(name, options = {}) {
  if (name == null || name.toString().length == 0) {
    return tooltip.info("The name parameter is invalid.", "");
  }

  $("#luckysheet_info_detail_input").val(name);

  let { success } = { ...options };

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 获取工作簿名称
 * @param   {Object}    options         可选参数
 * @param   {Function}  options.success 操作结束的回调函数
 * @returns {String}    返回工作簿名称，如果读取失败则返回空字符串并弹窗提示
 */
export function getWorkbookName(options = {}) {
  let name = "";
  let element = $("#luckysheet_info_detail_input");

  if (element.length == 0) {
    tooltip.info("Failed to get workbook name, label loading failed!");
    return name;
  }

  name = $.trim(element.val());

  let { success } = { ...options };

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 1);

  return name;
}

/**
 * 撤销当前操作，返回刚刚撤销的操作对象
 * @param {Object} options 可选参数
 * @param {Function} options.success 操作结束的回调函数
 */
export function undo(options = {}) {
  let ctr = $.extend(true, {}, Store.jfredo[Store.jfredo.length - 1]);

  controlHistory.redo(new Event("custom"));
  luckysheetactiveCell();

  let { success } = { ...options };

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 1);

  return ctr;
}

/**
 * 重做当前操作，返回刚刚重做的操作对象
 * @param {Object} options 可选参数
 * @param {Function} options.success 操作结束的回调函数
 */
export function redo(options = {}) {
  let ctr = $.extend(true, {}, Store.jfundo[Store.jfundo.length - 1]);

  controlHistory.undo(new Event("custom"));
  luckysheetactiveCell();

  let { success } = { ...options };

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 1);

  return ctr;
}

/**
 * 返回所有工作表配置
 */
export function getAllSheets() {
  let data = $.extend(true, [], Store.luckysheetfile);

  data.forEach((item, index, arr) => {
    if (item.data != null && item.data.length > 0) {
      item.celldata = sheetmanage.getGridData(item.data);
    }

    delete item.load;
    delete item.freezen;
  });

  return data;
}

/**
 * 根据index获取sheet页配置
 *
 * @param {Object} options 可选参数
 * @param {String} options.index 工作表index
 * @param {Number} options.order 工作表order
 * @param {String} options.name 工作表name
 */
export function getSheet(options = {}) {
  let { index, order, name } = { ...options };

  if (index != null) {
    return sheetmanage.getSheetByIndex(index);
  } else if (order != null) {
    return Store.luckysheetfile[order];
  } else if (name != null) {
    return sheetmanage.getSheetByName(name);
  }

  return sheetmanage.getSheetByIndex();
}

/**
 * 快捷返回指定工作表的数据
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 */
export function getSheetData(options = {}) {
  let { order = getSheetIndex(Store.currentSheetIndex) } = { ...options };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  let data = $.extend(true, [], file.data);

  if (data == null || data.length == 0) {
    data = $.extend(true, [], sheetmanage.buildGridData(file));
  }

  return data;
}

/**
 * 快捷返回指定工作表的config配置
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 */
export function getConfig(options = {}) {
  let { order = getSheetIndex(Store.currentSheetIndex) } = { ...options };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  let config = $.extend(true, {}, file.config);

  return config;
}

/**
 * 快捷设置指定工作表config配置
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 * @param {Function} options.success 操作结束的回调函数
 */
export function setConfig(cfg, options = {}) {
  if (getObjType(cfg) != "object") {
    return tooltip.info("The cfg parameter is invalid.", "");
  }

  let { order = getSheetIndex(Store.currentSheetIndex), success } = {
    ...options,
  };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  file.config = cfg;

  if (file.index == Store.currentSheetIndex) {
    Store.config = cfg;

    if (
      "rowhidden" in cfg ||
      "colhidden" in cfg ||
      "rowlen" in cfg ||
      "columnlen" in cfg
    ) {
      jfrefreshgrid_rhcw(Store.flowdata.length, Store.flowdata[0].length);
    }

    setTimeout(function() {
      luckysheetrefreshgrid();
    }, 1);
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 返回所有表格数据结构的一维数组luckysheetfile
 */
export function getLuckysheetfile() {
  return getluckysheetfile();
}

/**
 * 指定工作表范围设置数据验证功能，并设置参数
 * @param {Object} optionItem 数据验证的配置信息
 * @param {String} optionItem.type 类型
 * @param {String | Null} optionItem.type2 条件类型
 * @param {String | Number} optionItem.value1 条件值1
 * @param {String | Number} optionItem.value2 条件值2
 * @param {Boolean} optionItem.checked 选中状态
 * @param {Boolean} optionItem.remote 自动远程获取选项
 * @param {Boolean} optionItem.prohibitInput 输入数据无效时禁止输入
 * @param {Boolean} optionItem.hintShow 选中单元格时显示提示语
 * @param {String} optionItem.hintText 提示语文本
 * @param {Object} options 可选参数
 * @param {Array | Object | String} options.range 选区范围；默认为当前选区
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 * @param {Function} options.success 操作结束的回调函数
 */
export function setDataVerification(optionItem, options = {}) {
  if (getObjType(optionItem) != "object") {
    return tooltip.info("The optionItem parameter is invalid.", "");
  }

  let {
    type,
    type2 = null,
    value1 = "",
    value2 = "",
    remote = false,
    prohibitInput = false,
    hintShow = false,
    hintText = "",
    checked = false,
  } = { ...optionItem };

  let typeValues = [
    "dropdown",
    "checkbox",
    "number",
    "number_integer",
    "number_decimal",
    "text_content",
    "text_length",
    "date",
    "validity",
  ];
  let type2Values_1 = ["bw", "nb", "eq", "ne", "gt", "lt", "gte", "lte"];
  let type2Values_2 = ["include", "exclude", "equal"];
  let type2Values_3 = ["bw", "nb", "eq", "ne", "bf", "nbf", "af", "naf"];
  let type2Values_4 = ["card", "phone"];

  if (!typeValues.includes(type)) {
    return tooltip.info("The optionItem.type parameter is invalid.", "");
  }

  let dvText = locale().dataVerification;

  if (type == "dropdown") {
    if (value1.length == 0) {
      tooltip.info(
        '<i class="fa fa-exclamation-triangle"></i>',
        dvText.tooltipInfo1
      );
      return;
    }
  } else if (type == "checkbox") {
    if (value1.length == 0 || value2.length == 0) {
      tooltip.info(
        '<i class="fa fa-exclamation-triangle"></i>',
        dvText.tooltipInfo2
      );
      return;
    }
  } else if (
    type == "number" ||
    type == "number_integer" ||
    type == "number_decimal"
  ) {
    if (!type2Values_1.includes(type2)) {
      return tooltip.info("The optionItem.type2 parameter is invalid.", "");
    }

    if (!isRealNum(value1)) {
      tooltip.info(
        '<i class="fa fa-exclamation-triangle"></i>',
        dvText.tooltipInfo3
      );
      return;
    }

    if (type2 == "bw" || type2 == "nb") {
      if (!isRealNum(value2)) {
        tooltip.info(
          '<i class="fa fa-exclamation-triangle"></i>',
          dvText.tooltipInfo3
        );
        return;
      }

      if (Number(value2) < Number(value1)) {
        tooltip.info(
          '<i class="fa fa-exclamation-triangle"></i>',
          dvText.tooltipInfo4
        );
        return;
      }
    }
  } else if (type == "text_content") {
    if (!type2Values_2.includes(type2)) {
      return tooltip.info("The optionItem.type2 parameter is invalid.", "");
    }

    if (value1.length == 0) {
      tooltip.info(
        '<i class="fa fa-exclamation-triangle"></i>',
        dvText.tooltipInfo5
      );
      return;
    }
  } else if (type == "text_length") {
    if (!type2Values_1.includes(type2)) {
      return tooltip.info("The optionItem.type2 parameter is invalid.", "");
    }

    if (!isRealNum(value1)) {
      tooltip.info(
        '<i class="fa fa-exclamation-triangle"></i>',
        dvText.tooltipInfo3
      );
      return;
    }

    if (type2 == "bw" || type2 == "nb") {
      if (!isRealNum(value2)) {
        tooltip.info(
          '<i class="fa fa-exclamation-triangle"></i>',
          dvText.tooltipInfo3
        );
        return;
      }

      if (Number(value2) < Number(value1)) {
        tooltip.info(
          '<i class="fa fa-exclamation-triangle"></i>',
          dvText.tooltipInfo4
        );
        return;
      }
    }
  } else if (type == "date") {
    if (!type2Values_3.includes(type2)) {
      return tooltip.info("The optionItem.type2 parameter is invalid.", "");
    }

    if (!isdatetime(value1)) {
      tooltip.info(
        '<i class="fa fa-exclamation-triangle"></i>',
        dvText.tooltipInfo6
      );
      return;
    }

    if (type2 == "bw" || type2 == "nb") {
      if (!isdatetime(value2)) {
        tooltip.info(
          '<i class="fa fa-exclamation-triangle"></i>',
          dvText.tooltipInfo6
        );
        return;
      }

      if (diff(value1, value2) > 0) {
        tooltip.info(
          '<i class="fa fa-exclamation-triangle"></i>',
          dvText.tooltipInfo7
        );
        return;
      }
    }
  } else if (type == "validity") {
    if (!type2Values_4.includes(type2)) {
      return tooltip.info("The optionItem.type2 parameter is invalid.", "");
    }
  }

  if (getObjType(remote) != "boolean") {
    return tooltip.info("The optionItem.remote parameter is invalid.", "");
  }

  if (getObjType(prohibitInput) != "boolean") {
    return tooltip.info(
      "The optionItem.prohibitInput parameter is invalid.",
      ""
    );
  }

  if (getObjType(hintShow) != "boolean") {
    return tooltip.info("The optionItem.hintShow parameter is invalid.", "");
  }

  let {
    range = Store.luckysheet_select_save[
      Store.luckysheet_select_save.length - 1
    ],
    order = getSheetIndex(Store.currentSheetIndex),
    success,
  } = { ...options };

  if (getObjType(range) == "string") {
    if (!formula.iscelldata(range)) {
      return tooltip.info("The range parameter is invalid.", "");
    }

    let cellrange = formula.getcellrange(range);
    range = {
      row: cellrange.row,
      column: cellrange.column,
    };
  }

  if (
    getObjType(range) != "object" ||
    range.row == null ||
    range.column == null
  ) {
    return tooltip.info("The range parameter is invalid.", "");
  }

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  let item = {
    type: type,
    type2: type2,
    value1: value1,
    value2: value2,
    checked: checked,
    remote: remote,
    prohibitInput: prohibitInput,
    hintShow: hintShow,
    hintText: hintText,
  };

  let currentDataVerification = $.extend(true, {}, file.dataVerification);

  let data = $.extend(true, [], file.data);
  if (data.length == 0) {
    data = sheetmanage.buildGridData(file);
  }

  let str = range.row[0],
    edr = range.row[1],
    stc = range.column[0],
    edc = range.column[1];

  for (let r = str; r <= edr; r++) {
    for (let c = stc; c <= edc; c++) {
      currentDataVerification[r + "_" + c] = item;

      if (type == "checkbox") {
        item.checked
          ? setcellvalue(r, c, data, item.value1)
          : setcellvalue(r, c, data, item.value2);
      }
    }
  }

  if (file.index == Store.currentSheetIndex) {
    let historyDataVerification = $.extend(true, {}, file.dataVerification);

    if (type == "checkbox") {
      dataVerificationCtrl.refOfCheckbox(
        historyDataVerification,
        currentDataVerification,
        Store.currentSheetIndex,
        data,
        range
      );
    } else {
      dataVerificationCtrl.ref(
        historyDataVerification,
        currentDataVerification,
        Store.currentSheetIndex
      );
    }
  } else {
    file.dataVerification = currentDataVerification;
    file.data = data;
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 指定工作表范围删除数据验证功能
 * @param {Object} options 可选参数
 * @param {Array | Object | String} options.range 选区范围；默认为当前选区
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 * @param {Function} options.success 操作结束的回调函数
 */
export function deleteDataVerification(options = {}) {
  let {
    range = Store.luckysheet_select_save[
      Store.luckysheet_select_save.length - 1
    ],
    order = getSheetIndex(Store.currentSheetIndex),
    success,
  } = { ...options };

  if (getObjType(range) == "string") {
    if (!formula.iscelldata(range)) {
      return tooltip.info("The range parameter is invalid.", "");
    }

    let cellrange = formula.getcellrange(range);
    range = {
      row: cellrange.row,
      column: cellrange.column,
    };
  }

  if (
    getObjType(range) != "object" ||
    range.row == null ||
    range.column == null
  ) {
    return tooltip.info("The range parameter is invalid.", "");
  }

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  let currentDataVerification = $.extend(true, {}, file.dataVerification);

  let str = range.row[0],
    edr = range.row[1],
    stc = range.column[0],
    edc = range.column[1];

  for (let r = str; r <= edr; r++) {
    for (let c = stc; c <= edc; c++) {
      delete currentDataVerification[r + "_" + c];
    }
  }

  if (file.index == Store.currentSheetIndex) {
    let historyDataVerification = $.extend(true, {}, file.dataVerification);
    dataVerificationCtrl.ref(
      historyDataVerification,
      currentDataVerification,
      Store.currentSheetIndex
    );
  } else {
    file.dataVerification = currentDataVerification;
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 在指定的工作表中指定单元格位置插入图片
 * @param {String} src 图片src
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 * @param {Number} options.rowIndex 要插入图片的单元格行下标；默认为0
 * @param {Number} options.colIndex 要插入图片的单元格列下标；默认为0
 * @param {Function} options.success 操作结束的回调函数
 */
export function insertImage(src, options = {}) {
  let {
    order = getSheetIndex(Store.currentSheetIndex),
    rowIndex,
    colIndex,
    success,
  } = { ...options };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  if (file.index == Store.currentSheetIndex) {
    let last =
      Store.luckysheet_select_save[Store.luckysheet_select_save.length - 1];

    if (rowIndex == null) {
      rowIndex = last.row_focus || 0;
    }

    if (rowIndex < 0) {
      rowIndex = 0;
    }

    if (rowIndex > Store.visibledatarow.length) {
      rowIndex = Store.visibledatarow.length;
    }

    if (colIndex == null) {
      colIndex = last.column_focus || 0;
    }

    if (colIndex < 0) {
      colIndex = 0;
    }

    if (colIndex > Store.visibledatacolumn.length) {
      colIndex = Store.visibledatacolumn.length;
    }

    let left = colIndex == 0 ? 0 : Store.visibledatacolumn[colIndex - 1];
    let top = rowIndex == 0 ? 0 : Store.visibledatarow[rowIndex - 1];

    let image = new Image();
    image.onload = function() {
      let width = image.width,
        height = image.height;

      let img = {
        src: src,
        left: left,
        top: top,
        originWidth: width,
        originHeight: height,
      };

      imageCtrl.addImgItem(img);

      if (success && typeof success === "function") {
        success();
      }
    };
    image.src = src;
  } else {
    let images = file.images || {};
    let config = file.config;
    let zoomRatio = file.zoomRatio || 1;

    let rowheight = file.row;
    let visibledatarow = file.visibledatarow || [];
    if (visibledatarow.length === 0) {
      let rh_height = 0;

      for (let r = 0; r < rowheight; r++) {
        let rowlen = Store.defaultrowlen;

        if (config["rowlen"] != null && config["rowlen"][r] != null) {
          rowlen = config["rowlen"][r];
        }

        if (config["rowhidden"] != null && config["rowhidden"][r] != null) {
          visibledatarow.push(rh_height);
          continue;
        }

        rh_height += Math.round((rowlen + 1) * zoomRatio);

        visibledatarow.push(rh_height); //行的临时长度分布
      }
    }

    let colwidth = file.column;
    let visibledatacolumn = file.visibledatacolumn || [];
    if (visibledatacolumn.length === 0) {
      let ch_width = 0;

      for (let c = 0; c < colwidth; c++) {
        let firstcolumnlen = Store.defaultcollen;

        if (config["columnlen"] != null && config["columnlen"][c] != null) {
          firstcolumnlen = config["columnlen"][c];
        }

        if (config["colhidden"] != null && config["colhidden"][c] != null) {
          visibledatacolumn.push(ch_width);
          continue;
        }

        ch_width += Math.round((firstcolumnlen + 1) * zoomRatio);

        visibledatacolumn.push(ch_width); //列的临时长度分布
      }
    }

    if (rowIndex == null) {
      rowIndex = 0;
    }

    if (rowIndex < 0) {
      rowIndex = 0;
    }

    if (rowIndex > visibledatarow.length) {
      rowIndex = visibledatarow.length;
    }

    if (colIndex == null) {
      colIndex = 0;
    }

    if (colIndex < 0) {
      colIndex = 0;
    }

    if (colIndex > visibledatacolumn.length) {
      colIndex = visibledatacolumn.length;
    }

    let left = colIndex == 0 ? 0 : visibledatacolumn[colIndex - 1];
    let top = rowIndex == 0 ? 0 : visibledatarow[rowIndex - 1];

    let image = new Image();
    image.onload = function() {
      let img = {
        src: src,
        left: left,
        top: top,
        originWidth: image.width,
        originHeight: image.height,
      };

      let width, height;
      let max = 400;

      if (img.originHeight < img.originWidth) {
        height = Math.round(img.originHeight * (max / img.originWidth));
        width = max;
      } else {
        width = Math.round(img.originWidth * (max / img.originHeight));
        height = max;
      }

      let imgItem = $.extend(true, {}, imageCtrl.imgItem);
      imgItem.src = img.src;
      imgItem.originWidth = img.originWidth;
      imgItem.originHeight = img.originHeight;
      imgItem.default.width = width;
      imgItem.default.height = height;
      imgItem.default.left = img.left;
      imgItem.default.top = img.top;
      imgItem.crop.width = width;
      imgItem.crop.height = height;

      let id = imageCtrl.generateRandomId();
      images[id] = imgItem;

      file.images = images;

      if (success && typeof success === "function") {
        success();
      }
    };
    image.src = src;
  }
}

/**
 * 删除指定工作表中的图片
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 * @param {String | Array} options.idList 要删除图片的id集合，也可为字符串`"all"`，all为所有的字符串；默认为`"all"`
 * @param {Function} options.success 操作结束的回调函数
 */
export function deleteImage(options = {}) {
  let {
    order = getSheetIndex(Store.currentSheetIndex),
    idList = "all",
    success,
  } = { ...options };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  let images = file.images;

  if (images == null) {
    return tooltip.info("The worksheet has no pictures to delete.", "");
  }

  if (idList != "all" && getObjType(idList) != "array") {
    return tooltip.info("The idList parameter is invalid.", "");
  }

  if (getObjType(idList) == "array") {
    idList.forEach((item) => {
      delete images[item];
    });
  } else {
    images = null;
  }

  file.images = images;

  if (file.index == Store.currentSheetIndex) {
    if (
      imageCtrl.currentImgId != null &&
      (idList == "all" || idList.includes(imageCtrl.currentImgId))
    ) {
      $("#luckysheet-modal-dialog-activeImage").hide();
      $("#luckysheet-modal-dialog-cropping").hide();
      $("#luckysheet-modal-dialog-slider-imageCtrl").hide();
    }

    imageCtrl.images = images;
    imageCtrl.allImagesShow();
    imageCtrl.init();
  }

  if (success && typeof success === "function") {
    success();
  }
}

/**
 * 获取指定工作表的图片配置
 * @param {Object} options 可选参数
 * @param {Number} options.order 工作表下标；默认值为当前工作表下标
 * @param {Function} options.success 操作结束的回调函数
 */
export function getImageOption(options = {}) {
  let { order = getSheetIndex(Store.currentSheetIndex), success } = {
    ...options,
  };

  let file = Store.luckysheetfile[order];

  if (file == null) {
    return tooltip.info("The order parameter is invalid.", "");
  }

  setTimeout(function() {
    if (success && typeof success === "function") {
      success();
    }
  }, 1);

  return file.images;
}

/**
 * data => celldata ，data二维数组数据转化成 {r, c, v}格式一维数组
 *
 * @param {Array} data 二维数组数据
 * @param {Object} options 可选参数
 * @param {Function} options.success 操作结束的回调函数
 */
export function transToCellData(data, options = {}) {
  let { success } = { ...options };

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 0);

  return sheetmanage.getGridData(data);
}

/**
 * celldata => data ，celldata一维数组数据转化成表格所需二维数组
 *
 * @param {Array} celldata 二维数组数据
 * @param {Object} options 可选参数
 * @param {Function} options.success 操作结束的回调函数
 */
export function transToData(celldata, options = {}) {
  let { success } = { ...options };

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  }, 0);

  return sheetmanage.buildGridData({
    celldata: celldata,
  });
}

/**
 * 导出的json字符串可以直接当作`luckysheet.create(options)`初始化工作簿时的参数`options`使用
 *
 */
export function toJson() {
  const toJsonOptions = Store.toJsonOptions;

  // Workbook name
  toJsonOptions.title = $("#luckysheet_info_detail_input").val();

  toJsonOptions.data = getAllSheets();

  // row and column
  getluckysheetfile().forEach((file, index) => {
    if (file.data == undefined) {
      return;
    }
    toJsonOptions.data[index].row =
      getObjType(file.data) === "array" ? file.data.length : 0;
    toJsonOptions.data[index].column =
      getObjType(file.data[0]) === "array" ? file.data[0].length : 0;
  });

  return toJsonOptions;
}

/**
 * 传入目标语言，切换到对应的语言界面
 * @param {String} lang 可选参数；暂支持`"zh"`、`"en"`、`"es"`；默认为`"zh"`；
 */
export function changLang(lang = "zh") {
  if (!["zh", "en", "es"].includes(lang)) {
    return tooltip.info("The lang parameter is invalid.", "");
  }

  let options = toJson();
  options.lang = lang;
  luckysheet.create(options);
}

/**
 * 关闭websocket连接
 */
export function closeWebsocket() {
  if (server.websocket == null) {
    return;
  }
  server.websocket.close(1000);
}

/**
 * 根据范围字符串转换为range数组
 * @param {String} txt 范围字符串
 */
export function getRangeByTxt(txt) {
  // 默认取当前第一个范围
  if (txt == null) {
    return {
      column:
        Store.luckysheet_select_save[Store.luckysheet_select_save.length - 1]
          .column,
      row:
        Store.luckysheet_select_save[Store.luckysheet_select_save.length - 1]
          .row,
    };
  }

  const range = conditionformat.getRangeByTxt(txt);

  return {
    column: range[0].column,
    row: range[0].row,
  };
}

/**
 * 根据范围数组转换为范围字符串
 * @param {Object | Array} range 范围数组
 */
export function getTxtByRange(range = Store.luckysheet_select_save) {
  // 单个范围
  if (getObjType(range) === "object") {
    range = [range];
  }
  return conditionformat.getTxtByRange(range);
}

/**
 * 初始化分页器
 * @param {Object} config 分页器配置
 * @param {Number} config.pageIndex 当前的页码
 * @param {Number} config.pageSize 每页显示多少条数据
 * @param {Array} config.selectOption 选择每页的条数
 * @param {Number} config.total 总条数
 */
export function pagerInit(config) {
  const { prevPage, nextPage, total } = locale().button;
  $("#luckysheet-bottom-pager").remove();
  $("#luckysheet-sheet-content").after(
    '<div id="luckysheet-bottom-pager" style="font-size: 14px; margin-left: 10px; display: inline-block;"></div>'
  );
  $("#luckysheet-bottom-pager").sPage({
    page: config.pageIndex, //当前页码，必填
    total: config.total, //数据总条数，必填
    selectOption: config.selectOption, // 选择每页的行数，
    pageSize: config.pageSize, //每页显示多少条数据，默认10条
    showTotal: config.showTotal, // 是否显示总数，默认关闭：false
    showSkip: config.showSkip, //是否显示跳页，默认关闭：false
    showPN: config.showPN, //是否显示上下翻页，默认开启：true
    prevPage: config.prevPage || prevPage, //上翻页文字描述，默认"上一页"
    nextPage: config.nextPage || nextPage, //下翻页文字描述，默认"下一页"
    totalTxt: config.totalTxt || total + config.total, // 数据总条数文字描述，{total}为占位符，默认"总共：{total}"
    backFun: function(page) {
      page.pageIndex = page.page;
      if (!method.createHookFunction("onTogglePager", page)) {
        return;
      }
    },
  });
}

/**
 * 刷新公式
 * @param {Function} success 回调函数
 */
export function refreshFormula(success) {
  formula.execFunctionGroupForce(true);
  luckysheetrefreshgrid();
  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  });
}

/**
 * 更新sheet数据
 * @param {Array} data 工作簿配置，可以包含多个表
 * @param {Object} options 可选参数
 * @param {Function} options.success 操作结束的回调函数
 *
 */
export function updataSheet(options = {}) {
  let { data, success } = options;
  let files = Store.luckysheetfile;
  for (let i = 0; i < data.length; i++) {
    for (let j = 0; j < files.length; j++) {
      if (files[j].index === data[i].index) {
        files[j] = data[i];
      }
    }
  }
  let file = files[sheetmanage.getSheetIndex(Store.currentSheetIndex)],
    sheetData = sheetmanage.buildGridData(file);
  file.data = sheetData;

  if (!!file.isPivotTable) {
    Store.luckysheetcurrentisPivotTable = true;
    if (!isPivotInitial) {
      pivotTable.changePivotTable(index);
    }
  } else {
    Store.luckysheetcurrentisPivotTable = false;
    $("#luckysheet-modal-dialog-slider-pivot").hide();
    luckysheetsizeauto(false);
  }
  sheetmanage.mergeCalculation(file["index"]);
  sheetmanage.setSheetParam();
  setTimeout(function() {
    sheetmanage.showSheet();
    sheetmanage.restoreCache();
    formula.execFunctionGroupForce(luckysheetConfigsetting.forceCalculation);
    sheetmanage.restoreSheetAll(Store.currentSheetIndex);
    luckysheetrefreshgrid();
    if (success && typeof success === "function") {
      success();
    }
  }, 1);
  server.saveParam("shs", null, Store.currentSheetIndex);
}

/**
 * 刷新状态栏的状态
 * @param {Array}  data             操作数据
 * @param {Number} r                指定的行
 * @param {Number} c                指定的列
 * @param {Function} success        回调函数
 */
export function refreshMenuButtonFocus(data, r, c, success) {
  data = data || Store.flowdata;
  if (r == null && c == null) {
    /* 获取选取范围 */
    let last =
      Store.luckysheet_select_save[Store.luckysheet_select_save.length - 1];

    r = last.row_focus || last.row[0];
    c = last.column_focus || last.column[0];
  }

  menuButton.menuButtonFocus(data, r, c);

  setTimeout(() => {
    if (success && typeof success === "function") {
      success();
    }
  });
}

/**
 * 检查选区内所有cell指定类型的状态是否满足条件（主要是粗体、斜体、删除线和下划线等等）
 * @param {String}  type            类型
 * @param {String}  status          目标状态值
 */
export function checkTheStatusOfTheSelectedCells(type, status) {
  /* 获取选区内所有的单元格-扁平后的处理 */
  let cells = getRangeWithFlatten();

  let flag = cells.every(({ r, c }) => {
    let cell = Store.flowdata[r][c];
    if (cell == null) {
      return false;
    }
    return cell[type] == status;
  });

  return flag;
}
